Compare commits

...
39 Commits
Author SHA1 Message Date
github-actions[bot] db8434559e [CI Skip] release/stable 12.3.2
skip-checks: true
2023-06-12 05:27:44 +00:00
Jaco eaf9d97ae3 12.3.2 (#1846) 2023-06-12 08:20:17 +03:00
github-actions[bot] 3e6d86b768 [CI Skip] release/stable 12.3.1
skip-checks: true
2023-06-11 06:26:55 +00:00
Jaco 8aab41648e 12.3.1 (#1845) 2023-06-11 09:20:32 +03:00
github-actions[bot] 4a535c08c7 [CI Skip] bump/beta 12.2.3-3-x
skip-checks: true
2023-06-10 08:09:54 +00:00
Jaco 715486d54e Additional adjustments to keyring types (#1844) 2023-06-10 11:01:23 +03:00
github-actions[bot] 1073dc14aa [CI Skip] bump/beta 12.2.3-2-x
skip-checks: true
2023-06-10 04:50:38 +00:00
Jaco 5cca95e855 Adjust object index typings (#1843)
* Adjust object index typings

* Update packages/util/src/is/childClass.ts

* Expand meta definition

* Extend meta with extension info

* Adjust

* CHANGELOG
2023-06-10 07:44:28 +03:00
github-actions[bot] 942b623273 [CI Skip] bump/beta 12.2.3-1-x
skip-checks: true
2023-06-06 05:37:49 +00:00
Jaco eea99656ad Only allow padding characters in base64 strings (#1842)
* Only allow padding characters in base64 strings

* Explicit padding sequence error
2023-06-06 08:31:44 +03:00
github-actions[bot] 04b6df9ac5 [CI Skip] bump/beta 12.2.3-0-x
skip-checks: true
2023-06-05 18:29:35 +00:00
Carlo Sala d5132b56de feat(networks): add zeitgeist Ledger support (#1840)
* feat(networks): add zeitgeist Ledger support

* fix(networks): update test
2023-06-05 21:23:31 +03:00
github-actions[bot] 1fdc2c8dae [CI Skip] release/stable 12.2.2
skip-checks: true
2023-06-04 09:06:26 +00:00
Jaco b6a2693e5f 12.2.2 (#1839) 2023-06-04 11:58:18 +03:00
github-actions[bot] 8b3687e062 [CI Skip] bump/beta 12.2.2-7-x
skip-checks: true
2023-06-04 08:30:55 +00:00
Jaco 3a8429b687 Bump noble/{curves, hashes} (#1838) 2023-06-04 11:24:40 +03:00
github-actions[bot] 26e9b01198 [CI Skip] bump/beta 12.2.2-6-x
skip-checks: true
2023-06-02 10:51:44 +00:00
Jaco 76d71d946d Bump deps (w/ TS 5.1) (#1837)
* Bump deps (w/ TS 5.1)

* Adjust fallback

* Revert promisify adjustments
2023-06-02 13:44:54 +03:00
github-actions[bot] 0ebc7bd374 [CI Skip] bump/beta 12.2.2-5-x
skip-checks: true
2023-05-30 08:57:58 +00:00
Jaco d94c126744 Apply missing count assignment in for loops (#1836) 2023-05-30 11:50:04 +03:00
github-actions[bot] 86597dcb17 [CI Skip] bump/beta 12.2.2-4-x
skip-checks: true
2023-05-28 07:53:44 +00:00
Jaco 1be682827b Bump deps (incl Ledger) (#1835) 2023-05-28 10:47:42 +03:00
github-actions[bot] 081b6b4f2b [CI Skip] bump/beta 12.2.2-3-x
skip-checks: true
2023-05-25 07:37:17 +00:00
Jaco 7dc38e78cf jg-bump-deps (#1834) 2023-05-25 10:29:17 +03:00
github-actions[bot] dcf214f250 [CI Skip] bump/beta 12.2.2-2-x
skip-checks: true
2023-05-21 09:48:48 +00:00
Jaco 2e82528e1b Bump dev (w/ eslint config adj) (#1832) 2023-05-21 12:42:39 +03:00
github-actions[bot] 090b91910f [CI Skip] bump/beta 12.2.2-1-x
skip-checks: true
2023-05-18 09:05:38 +00:00
Jaco 058d197646 Adjust tsconfig usage (w/ latest dev) (#1831) 2023-05-18 11:59:17 +03:00
github-actions[bot] 0fca8904e6 [CI Skip] bump/beta 12.2.2-0-x
skip-checks: true
2023-05-18 05:35:04 +00:00
Jaco 0bf7bc416a Bump dev deps (#1830) 2023-05-18 08:29:07 +03:00
github-actions[bot] ea08763307 [CI Skip] release/stable 12.2.1
skip-checks: true
2023-05-13 08:25:36 +00:00
Jaco 5272645abe 12.2.1 (#1829) 2023-05-13 11:17:53 +03:00
Jaco e5373c35c8 Unroll u8aToBigInt loops (#1821)
* Unroll u8aToBigInt loops

* Bump dev

* Rolling tests
2023-05-13 10:51:46 +03:00
github-actions[bot] b73b96e412 [CI Skip] bump/beta 12.1.3-2-x
skip-checks: true
2023-05-06 09:00:28 +00:00
Jaco 18d24bf509 Bump dev (#1827) 2023-05-06 11:52:33 +03:00
github-actions[bot] fe230f143f [CI Skip] bump/beta 12.1.3-1-x
skip-checks: true
2023-05-05 07:07:53 +00:00
Jaco 6357c1e040 Update Constructor interface params (#1823)
* Update Constructor interface params

* Adjust

* Adjust
2023-05-05 10:01:56 +03:00
github-actions[bot] 1876efe13e [CI Skip] bump/beta 12.1.3-0-x
skip-checks: true
2023-05-05 06:46:01 +00:00
Jaco 9de142b5f6 Bump deps (#1826) 2023-05-05 09:39:58 +03:00
140 changed files with 1631 additions and 925 deletions
-2
View File
@@ -1,2 +0,0 @@
packages/x-noble-hashes/**/*.ts
packages/x-noble-secp256k1/**/*.ts
-22
View File
@@ -1,22 +0,0 @@
// Copyright 2017-2023 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
const base = require('@polkadot/dev/config/eslint.cjs');
module.exports = {
...base,
ignorePatterns: [
...base.ignorePatterns
],
parserOptions: {
...base.parserOptions,
project: [
'./tsconfig.eslint.json'
]
},
rules: {
...base.rules,
// this seems very broken atm, false positives
'@typescript-eslint/unbound-method': 'off'
}
};
+1 -1
View File
@@ -22,5 +22,5 @@ jobs:
- name: ${{ matrix.step }}
if: always()
run: |
yarn install --immutable | grep -v 'YN0013'
yarn install --immutable
yarn ${{ matrix.step }}
+1 -1
View File
@@ -27,5 +27,5 @@ jobs:
node-version: 'lts/*'
- name: ${{ matrix.step }}
run: |
yarn install --immutable | grep -v 'YN0013'
yarn install --immutable
yarn ${{ matrix.step }}
+5
View File
@@ -2,6 +2,11 @@ enableImmutableInstalls: false
enableProgressBars: false
logFilters:
# Discard any "cannot be found in cache" messages
- code: YN0013
level: discard
nodeLinker: node-modules
plugins:
+36
View File
@@ -1,5 +1,41 @@
# CHANGELOG
## 12.3.2 Jun 12, 2023
Changes:
- Adjust `SubstrateNetwork` typing with `HexString` genesisHash
- Re-export `Constructor<T>` type (deprecated, replaced with `Class<T>`)
## 12.3.1 Jun 11, 2023
Changes:
- Only allow padding characters in base64 strings
- Expand typings for keyring meta with known keys
- Adjust object index access for stricter tsconfig settings
## 12.2.2 Jun 4, 2023
Changes:
- Apply missing count assignment for `for (...)` loops
- Remove unused `@types/*` dev dependencies
- Upgrade dependencies to latest stable versions
## 12.2.1 May 13, 2023
Changes:
- Align `u8aToBigInt` tests with `u8aToBn`
- Unroll loops on most-frequently used paths for `u8aToBigInt`
- Add `module` to `package.json` export map (ESM-only)
- Upgrade dependencies to latest stable versions
## 12.1.2 May 1, 2023
Changes:
+2 -2
View File
@@ -1,5 +1,5 @@
1608 Jaco Fix typings for isChildClass (#1824)
12 Carlo Sala feat(networks): support ledger for pendulum (#1739)
1627 Jaco 12.3.2 (#1846)
13 Carlo Sala feat(networks): add zeitgeist Ledger support (#1840)
9 Antoine Estienne Add eth uri keyring test (#1291)
6 Amaury Martiny Add tests from Rust (#283)
5 Jakub Pánik Add HydraDX parachain to genesis (#1583)
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2017-2023 @polkadot/dev authors & contributors
// SPDX-License-Identifier: Apache-2.0
import baseConfig from '@polkadot/dev/config/eslint';
export default [
...baseConfig
];
+6 -6
View File
@@ -14,10 +14,10 @@
},
"sideEffects": false,
"type": "module",
"version": "12.1.2",
"version": "12.3.2",
"versions": {
"git": "12.1.2",
"npm": "12.1.2"
"git": "12.3.2",
"npm": "12.3.2"
},
"workspaces": [
"packages/*"
@@ -37,10 +37,10 @@
"test:one": "polkadot-dev-run-test --env browser"
},
"devDependencies": {
"@polkadot/dev": "^0.73.8",
"@types/node": "^18.16.3"
"@polkadot/dev": "^0.75.19",
"@types/node": "^20.3.0"
},
"resolutions": {
"typescript": "^5.0.4"
"typescript": "^5.1.3"
}
}
+7 -7
View File
@@ -14,18 +14,18 @@
},
"sideEffects": false,
"type": "module",
"version": "12.1.2",
"version": "12.3.2",
"browser": "browser.js",
"main": "node.js",
"react-native": "react-native.js",
"dependencies": {
"@ledgerhq/hw-transport": "^6.28.2",
"@ledgerhq/hw-transport-webhid": "^6.27.13",
"@ledgerhq/hw-transport-webusb": "^6.27.13",
"@polkadot/util": "12.1.2",
"tslib": "^2.5.0"
"@ledgerhq/hw-transport": "^6.28.4",
"@ledgerhq/hw-transport-webhid": "^6.27.15",
"@ledgerhq/hw-transport-webusb": "^6.27.15",
"@polkadot/util": "12.3.2",
"tslib": "^2.5.3"
},
"optionalDependencies": {
"@ledgerhq/hw-transport-node-hid-singleton": "^6.28.10"
"@ledgerhq/hw-transport-node-hid-singleton": "^6.28.12"
}
}
@@ -3,4 +3,4 @@
// Do not edit, auto-generated by @polkadot/dev
export const packageInfo = { name: '@polkadot/hw-ledger-transports', path: 'auto', type: 'auto', version: '12.1.2' };
export const packageInfo = { name: '@polkadot/hw-ledger-transports', path: 'auto', type: 'auto', version: '12.3.2' };
@@ -5,6 +5,9 @@
"outDir": "./build",
"rootDir": "./src"
},
"exclude": [
"**/mod.ts"
],
"references": [
{ "path": "../util/tsconfig.build.json" }
]
+4 -4
View File
@@ -17,12 +17,12 @@
"./detectPackage.cjs"
],
"type": "module",
"version": "12.1.2",
"version": "12.3.2",
"main": "index.js",
"dependencies": {
"@polkadot/hw-ledger-transports": "12.1.2",
"@polkadot/util": "12.1.2",
"@polkadot/hw-ledger-transports": "12.3.2",
"@polkadot/util": "12.3.2",
"@zondax/ledger-substrate": "^0.40.7",
"tslib": "^2.5.0"
"tslib": "^2.5.3"
}
}
+1 -1
View File
@@ -89,7 +89,7 @@ export class Ledger {
}
/**
* Signs a transcation on the Ledger device
* Signs a transaction on the Ledger device
*/
public async sign (message: Uint8Array, accountOffset = 0, addressOffset = 0, { account = LEDGER_DEFAULT_ACCOUNT, addressIndex = LEDGER_DEFAULT_INDEX, change = LEDGER_DEFAULT_CHANGE }: Partial<AccountOptions> = {}): Promise<LedgerSignature> {
return this.withApp(async (app: SubstrateApp): Promise<LedgerSignature> => {
+2 -1
View File
@@ -38,5 +38,6 @@ export const ledgerApps: Record<string, string> = {
ternoa: 'Ternoa',
unique: 'Unique',
vtb: 'VTB',
xxnetwork: 'XXNetwork'
xxnetwork: 'XXNetwork',
zeitgeist: 'Zeitgeist'
};
+1 -1
View File
@@ -3,4 +3,4 @@
// Do not edit, auto-generated by @polkadot/dev
export const packageInfo = { name: '@polkadot/hw-ledger', path: 'auto', type: 'auto', version: '12.1.2' };
export const packageInfo = { name: '@polkadot/hw-ledger', path: 'auto', type: 'auto', version: '12.3.2' };
+4
View File
@@ -5,6 +5,10 @@
"outDir": "./build",
"rootDir": "./src"
},
"exclude": [
"**/*.spec.ts",
"**/mod.ts"
],
"references": [
{ "path": "../hw-ledger-transports/tsconfig.build.json" },
{ "path": "../util/tsconfig.build.json" }
+16
View File
@@ -0,0 +1,16 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "..",
"outDir": "./build",
"rootDir": "./src",
"emitDeclarationOnly": false,
"noEmit": true
},
"include": [
"**/*.spec.ts"
],
"references": [
{ "path": "../hw-ledger/tsconfig.build.json" }
]
}
+6 -6
View File
@@ -18,15 +18,15 @@
"./detectPackage.cjs"
],
"type": "module",
"version": "12.1.2",
"version": "12.3.2",
"main": "index.js",
"dependencies": {
"@polkadot/util": "12.1.2",
"@polkadot/util-crypto": "12.1.2",
"tslib": "^2.5.0"
"@polkadot/util": "12.3.2",
"@polkadot/util-crypto": "12.3.2",
"tslib": "^2.5.3"
},
"peerDependencies": {
"@polkadot/util": "12.1.2",
"@polkadot/util-crypto": "12.1.2"
"@polkadot/util": "12.3.2",
"@polkadot/util-crypto": "12.3.2"
}
}
+1 -1
View File
@@ -3,4 +3,4 @@
// Do not edit, auto-generated by @polkadot/dev
export const packageInfo = { name: '@polkadot/keyring', path: 'auto', type: 'auto', version: '12.1.2' };
export const packageInfo = { name: '@polkadot/keyring', path: 'auto', type: 'auto', version: '12.3.2' };
+1 -1
View File
@@ -95,7 +95,7 @@ describe('keyring.addFromUri', (): void => {
for (const [type, tests] of Object.entries(TESTS)) {
const keyring = new Keyring({ type: type as KeypairType });
describe(type, (): void => {
describe(`${type}`, (): void => {
tests.forEach(({ pk, ss, uri }): void => {
it(`creates ${uri}`, (): void => {
const pair = keyring.addFromUri(uri, {}, type as KeypairType);
+14 -6
View File
@@ -47,7 +47,7 @@ describe('testingPairs', (): void => {
).toEqual(TEST_ADD);
});
it('checks eth test addresses', (): void => {
describe('checks eth test addresses', (): void => {
const ring = createTestPairs({ type: 'ethereum' });
const keyring = new Keyring({ type: 'ethereum' });
// priv keys generated by ganache-cli --mnemonic "bottom drive obey lake curtain smoke basket hold race lonely fit walk"
@@ -62,12 +62,20 @@ describe('testingPairs', (): void => {
'0x4c42532034540267bf568198ccec4cb822a025da542861fcb146a5fab6433ff8',
'0x94c49300a58d576011096bcb006aa06f5a91b34b4383891e8029c21dc39fbb8b'];
// @ts-expect-error We should not delete from the maps, however this is a test
delete ring.nobody;
Object.keys(ring).forEach((testKeyring, i) => {
if (i < 6) {
expect(u8aToHex(ring[testKeyring].publicKey)).toEqual(u8aToHex(keyring.createFromUri(privKeys[i]).publicKey));
}
});
Object
.keys(ring)
.filter((_, i) => i < 6)
.forEach((testKeyring, i) => {
it(`checks #${i}`, (): void => {
expect(
u8aToHex(ring[testKeyring].publicKey)
).toEqual(
u8aToHex(keyring.createFromUri(privKeys[i]).publicKey)
);
});
});
});
});
+33 -2
View File
@@ -1,16 +1,47 @@
// Copyright 2017-2023 @polkadot/keyring authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { KeypairType } from '@polkadot/util-crypto/types';
import type { KeyringOptions, KeyringPair } from './types.js';
import { nobody } from './pair/nobody.js';
import { createTestKeyring } from './testing.js';
export interface TestKeyringMap {
nobody: KeyringPair;
[index: string]: KeyringPair;
}
export function createTestPairs (options?: KeyringOptions, isDerived = true): TestKeyringMap {
export interface TestKeyringMapSubstrate extends TestKeyringMap {
alice: KeyringPair;
bob: KeyringPair;
charlie: KeyringPair;
dave: KeyringPair;
eve: KeyringPair;
ferdie: KeyringPair;
}
export interface TestKeyringMapEthereum extends TestKeyringMap {
Alith: KeyringPair;
Baltathar: KeyringPair;
Charleth: KeyringPair;
Dorothy: KeyringPair;
Ethan: KeyringPair;
Faith: KeyringPair;
}
export type DetectMap<O extends KeyringOptions | undefined> = DetectPairType<O> extends 'ethereum'
? TestKeyringMapEthereum
: TestKeyringMapSubstrate;
export type DetectPairType<O extends KeyringOptions | undefined> = O extends KeyringOptions
? O['type'] extends KeypairType
? O['type']
: 'sr25519'
: 'sr25519';
export function createTestPairs <O extends KeyringOptions, M = DetectMap<O>> (options?: O, isDerived = true): M {
const keyring = createTestKeyring(options, isDerived);
const pairs = keyring.getPairs();
const map: TestKeyringMap = { nobody: nobody() };
@@ -19,5 +50,5 @@ export function createTestPairs (options?: KeyringOptions, isDerived = true): Te
map[p.meta.name as string] = p;
}
return map;
return map as M;
}
+52 -1
View File
@@ -15,7 +15,58 @@ export interface KeyringOptions {
type?: KeypairType;
}
export type KeyringPair$Meta = Record<string, unknown>;
export interface KeyringPair$MetaHardware {
accountIndex?: number;
accountOffset?: number;
addressOffset?: number;
hardwareType?: 'ledger';
}
export interface KeyringPair$MetaFlags {
isDefaultAuthSelected?: boolean;
isExternal?: boolean;
isHardware?: boolean;
isHidden?: boolean;
isInjected?: boolean;
isMultisig?: boolean;
isProxied?: boolean;
isRecent?: boolean;
isTesting?: boolean;
}
export interface KeyringPair$MetaContract {
abi: string;
genesisHash?: HexString | null;
}
export interface KeyringPair$MetaExtension {
source?: string;
}
export interface KeyringPair$MetaMultisig {
threshold?: number;
who?: string[];
}
export interface KeyringPair$MetaParent {
parentAddress?: string;
parentName?: string;
}
export interface KeyringPair$Meta extends KeyringPair$MetaExtension, KeyringPair$MetaFlags, KeyringPair$MetaHardware, KeyringPair$MetaMultisig, KeyringPair$MetaParent {
address?: string;
contract?: KeyringPair$MetaContract;
genesisHash?: HexString | null;
name?: string;
suri?: string;
tags?: string[];
type?: KeypairType;
whenCreated?: number;
whenEdited?: number;
whenUsed?: number;
[key: string]: unknown;
}
export interface KeyringPair$Json extends EncryptedJson {
/** The ss58 encoded address or the hex-encoded version (the latter is for ETH-compat chains) */
+4
View File
@@ -5,6 +5,10 @@
"outDir": "./build",
"rootDir": "./src"
},
"exclude": [
"**/*.spec.ts",
"**/mod.ts"
],
"references": [
{ "path": "../util/tsconfig.build.json" },
{ "path": "../util-crypto/tsconfig.build.json" }
+18
View File
@@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "..",
"outDir": "./build",
"rootDir": "./src",
"emitDeclarationOnly": false,
"noEmit": true
},
"include": [
"**/*.spec.ts"
],
"references": [
{ "path": "../keyring/tsconfig.build.json" },
{ "path": "../util/tsconfig.build.json" },
{ "path": "../util-crypto/tsconfig.build.json" }
]
}
+4 -4
View File
@@ -15,14 +15,14 @@
},
"sideEffects": false,
"type": "module",
"version": "12.1.2",
"version": "12.3.2",
"main": "index.js",
"dependencies": {
"@polkadot/util": "12.1.2",
"@polkadot/util": "12.3.2",
"@substrate/ss58-registry": "^1.40.0",
"tslib": "^2.5.0"
"tslib": "^2.5.3"
},
"devDependencies": {
"@polkadot/hw-ledger": "12.1.2"
"@polkadot/hw-ledger": "12.3.2"
}
}
@@ -157,5 +157,8 @@ export const knownGenesis: KnownGenesis = {
],
xxnetwork: [
'0x50dd5d206917bf10502c68fb4d18a59fc8aa31586f4e8856b493e43544aa82aa'
],
zeitgeist: [
'0x1bf2a2ecb4a868de66ea8610f2ce7c8c43706561b6476031315f6640fe38e060'
]
};
+2 -1
View File
@@ -42,5 +42,6 @@ export const knownLedger: KnownLedger = {
ternoa: 0x00003e3,
unique: 0x00000162,
vtb: 0x000002b6,
xxnetwork: 0x000007a3
xxnetwork: 0x000007a3,
zeitgeist: 0x00000162
};
+1 -1
View File
@@ -115,6 +115,6 @@ describe('selectableNetworks', (): void => {
it('has a sorted list (first external, last external)', (): void => {
expect(selectableNetworks[3].displayName).toEqual('3DP network');
expect(selectableNetworks[selectableNetworks.length - 1].displayName).toEqual('xx network');
expect(selectableNetworks[selectableNetworks.length - 1].displayName).toEqual('Zeitgeist');
});
});
+1 -1
View File
@@ -3,4 +3,4 @@
// Do not edit, auto-generated by @polkadot/dev
export const packageInfo = { name: '@polkadot/networks', path: 'auto', type: 'auto', version: '12.1.2' };
export const packageInfo = { name: '@polkadot/networks', path: 'auto', type: 'auto', version: '12.3.2' };
+3 -3
View File
@@ -7,7 +7,7 @@ import known from '@substrate/ss58-registry';
import fs from 'node:fs';
import path from 'node:path';
const other = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'packages/networks/src/test/ss58registry.test.json'), 'utf-8')) as unknown;
const other = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'packages/networks/test/ss58registry.json'), 'utf-8')) as unknown;
describe('@substrate/ss58-registry', (): void => {
it('has known values', (): void => {
@@ -16,13 +16,13 @@ describe('@substrate/ss58-registry', (): void => {
try {
expect(JSON.parse(json)).toEqual(other);
} catch (error) {
if (process.env.GITHUB_REPOSITORY) {
if (process.env['GITHUB_REPOSITORY']) {
console.error(json);
throw error;
}
fs.writeFileSync(path.join(process.cwd(), 'packages/networks/src/test/ss58registry.test.json'), json, { flag: 'w' });
fs.writeFileSync(path.join(process.cwd(), 'packages/networks/test/ss58registry.json'), json, { flag: 'w' });
}
});
});
+3 -2
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type { RegistryEntry } from '@substrate/ss58-registry';
import type { HexString } from '@polkadot/util/types';
export type Icon = 'beachball' | 'empty' | 'jdenticon' | 'polkadot' | 'substrate';
@@ -9,14 +10,14 @@ export type KnownIcon = Record<string, Icon>;
export type KnownLedger = Record<string, number>;
export type KnownGenesis = Record<string, string[]>;
export type KnownGenesis = Record<string, HexString[]>;
export type KnownSubstrate = RegistryEntry;
export type KnownTestnet = Record<string, true>;
export interface SubstrateNetwork extends KnownSubstrate {
genesisHash: string[];
genesisHash: HexString[];
hasLedgerSupport: boolean;
icon: Icon;
isIgnored: boolean;
+4 -3
View File
@@ -5,9 +5,10 @@
"outDir": "./build",
"rootDir": "./src"
},
"include": [
"**/src/**/*.ts",
"**/test/*.json"
"exclude": [
"**/*.spec.ts",
"**/test/*",
"**/mod.ts"
],
"references": [
{ "path": "../hw-ledger/tsconfig.build.json" },
+18
View File
@@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "..",
"outDir": "./build",
"rootDir": "./src",
"emitDeclarationOnly": false,
"noEmit": true
},
"include": [
"**/*.spec.ts"
],
"references": [
{ "path": "../hw-ledger/tsconfig.build.json" },
{ "path": "../networks/tsconfig.build.json" },
{ "path": "../util/tsconfig.build.json" }
]
}
+11 -11
View File
@@ -20,25 +20,25 @@
"./detectPackage.cjs"
],
"type": "module",
"version": "12.1.2",
"version": "12.3.2",
"browser": {
"crypto": false,
"stream": false
},
"main": "index.js",
"dependencies": {
"@noble/curves": "1.0.0",
"@noble/hashes": "1.3.0",
"@polkadot/networks": "12.1.2",
"@polkadot/util": "12.1.2",
"@polkadot/wasm-crypto": "^7.1.2",
"@polkadot/wasm-util": "^7.1.2",
"@polkadot/x-bigint": "12.1.2",
"@polkadot/x-randomvalues": "12.1.2",
"@noble/curves": "1.1.0",
"@noble/hashes": "1.3.1",
"@polkadot/networks": "12.3.2",
"@polkadot/util": "12.3.2",
"@polkadot/wasm-crypto": "^7.2.1",
"@polkadot/wasm-util": "^7.2.1",
"@polkadot/x-bigint": "12.3.2",
"@polkadot/x-randomvalues": "12.3.2",
"@scure/base": "1.1.1",
"tslib": "^2.5.0"
"tslib": "^2.5.3"
},
"peerDependencies": {
"@polkadot/util": "12.1.2"
"@polkadot/util": "12.3.2"
}
}
@@ -5,8 +5,10 @@
import { encodeAddress } from './index.js';
// eslint-disable-next-line jest/no-export
export const ALICE_PUBLIC_SR = new Uint8Array([212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125]);
// eslint-disable-next-line jest/no-export
export const ALICE_PUBLIC_ED = new Uint8Array([209, 114, 167, 76, 218, 76, 134, 89, 18, 195, 43, 160, 168, 10, 87, 174, 105, 171, 174, 65, 14, 92, 203, 89, 222, 232, 78, 47, 68, 50, 219, 79]);
const SUBKEY = [
+14 -8
View File
@@ -19,6 +19,7 @@ interface Config {
ipfs?: string;
regex?: RegExp;
type: string;
withPadding?: boolean;
}
type DecodeFn = (value: string, ipfsCompat?: boolean) => Uint8Array;
@@ -63,7 +64,7 @@ export function createIs (validate: ValidateFn): ValidateFn {
}
/** @internal */
export function createValidate ({ chars, ipfs, type }: Config): ValidateFn {
export function createValidate ({ chars, ipfs, type, withPadding }: Config): ValidateFn {
return (value?: unknown, ipfsCompat?: boolean): value is string => {
if (typeof value !== 'string') {
throw new Error(`Expected ${type} string input`);
@@ -71,13 +72,18 @@ export function createValidate ({ chars, ipfs, type }: Config): ValidateFn {
throw new Error(`Expected ipfs-compatible ${type} to start with '${ipfs}'`);
}
for (let i = (ipfsCompat ? 1 : 0); i < value.length; i++) {
if (!(chars.includes(value[i]) || (
value[i] === '=' && (
(i === value.length - 1) ||
!chars.includes(value[i + 1])
)
))) {
for (let i = (ipfsCompat ? 1 : 0), count = value.length; i < count; i++) {
if (chars.includes(value[i])) {
// all ok, character found
} else if (withPadding && value[i] === '=') {
if (i === count - 1) {
// last character, everything ok
} else if (value[i + 1] === '=') {
// next one is also padding, sequence ok
} else {
throw new Error(`Invalid ${type} padding sequence "${value[i]}${value[i + 1]}" at index ${i}`);
}
} else {
throw new Error(`Invalid ${type} character "${value[i]}" (0x${value.charCodeAt(i).toString(16)}) at index ${i}`);
}
}
@@ -0,0 +1,20 @@
// Copyright 2017-2023 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@polkadot/dev-test/globals.d.ts" />
import { base58Validate } from './index.js';
describe('base58Validate', (): void => {
it('validates encoded', (): void => {
expect(
base58Validate('a1UbyspTdnyZXLUQaQbciCxrCWWxz24kgSwGXSQnkbs', false)
).toEqual(true);
});
it('fails on string with extra padding', (): void => {
expect(
() => base58Validate('a1UbyspTdnyZXLUQaQbciCxrCWWxz24kgSwGXSQnkbs=', false)
).toThrow(/Invalid base58 character "="/);
});
});
+2 -1
View File
@@ -8,7 +8,8 @@ import { createDecode, createEncode, createIs, createValidate } from '../base32/
const config = {
chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
coder: base64,
type: 'base64'
type: 'base64',
withPadding: true
};
/**
@@ -11,4 +11,22 @@ describe('base64Validate', (): void => {
() => base64Validate('aGVsbG8gd29ybGQg0J/RgNC40LLQtd^GC0YHRgtCy0YPRjiDQvNC4IOS9oOWlvQ==')
).toThrow(/Invalid base64 character "\^" \(0x5e\) at index 30/);
});
it('validates with one extra padding character', (): void => {
expect(
base64Validate('bGlnaHQgd28=')
).toEqual(true);
});
it('validates with two extra padding characters', (): void => {
expect(
base64Validate('bGlnaHQgdw==')
).toEqual(true);
});
it('validates misplaced padding characters', (): void => {
expect(
() => base64Validate('bGlnaHQgdw=g=')
).toThrow(/Invalid base64 padding sequence "=g"/);
});
});
-3
View File
@@ -3,9 +3,6 @@
/// <reference types="@polkadot/dev-test/globals.d.ts" />
// no TS, this is not meant to be a global...
export {};
describe('cryptoWaitReady', (): void => {
it('should return false when it cannot initialize', async (): Promise<void> => {
const old = global.WebAssembly;
@@ -37,13 +37,13 @@ describe('keyExtractPath', (): void => {
expect(test.path[1].chainCode).toEqual(Uint8Array.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
});
it('does not extract from invalid paths', (): void => {
it('does not extract from invalid paths (1)', (): void => {
expect(
(): ExtractResult => keyExtractPath('1/2')
).toThrow(/does not match input/);
});
it('does not extract from invalid paths', (): void => {
it('does not extract from invalid paths (2)', (): void => {
expect(
(): ExtractResult => keyExtractPath('hello')
).toThrow(/does not match input/);
@@ -28,7 +28,7 @@ for (const onlyJsMnemonic of [false, true]) {
// NOTE we cannot actually use the onlyJsMnemonic flag here
const mnemonic = mnemonicGenerate(12);
describe(mnemonic, (): void => {
describe(`${mnemonic}`, (): void => {
// do iterations to check and re-check that all matches
for (const count of arrayRange(NUM_CHECKS)) {
it(`check=${count + 1}`, (): void => {
+1 -1
View File
@@ -3,4 +3,4 @@
// Do not edit, auto-generated by @polkadot/dev
export const packageInfo = { name: '@polkadot/util-crypto', path: 'auto', type: 'auto', version: '12.1.2' };
export const packageInfo = { name: '@polkadot/util-crypto', path: 'auto', type: 'auto', version: '12.3.2' };
@@ -9,10 +9,13 @@ import { perfWasm } from '../test/index.js';
import { DEFAULT_PARAMS } from './defaults.js';
import { scryptEncode } from './index.js';
// eslint-disable-next-line jest/no-export
export const KNOWN_TEST = 'testing, 123';
// eslint-disable-next-line jest/no-export
export const KNOWN_PASS = new Uint8Array([223, 185, 241, 135, 125, 17, 195, 27, 64, 64, 154, 69, 47, 82, 123, 38, 255, 230, 199, 200, 101, 115, 21, 116, 119, 59, 67, 43, 58, 220, 112, 70, 124, 139, 240, 206, 42, 148, 140, 132, 64, 226, 164, 25, 104, 80, 49, 92, 144, 132, 109, 178, 76, 225, 171, 116, 151, 181, 34, 243, 177, 235, 134, 76]);
// eslint-disable-next-line jest/no-export
export const KNOWN_SALT = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8]);
describe('scryptEncode', (): void => {
@@ -153,6 +153,7 @@ const tests: Test[] = [
]
];
// eslint-disable-next-line jest/no-export
export default tests;
it('has a test', (): void => {
+4
View File
@@ -5,6 +5,10 @@
"outDir": "./build",
"rootDir": "./src"
},
"exclude": [
"**/mod.ts",
"**/*.spec.ts"
],
"references": [
{ "path": "../networks/tsconfig.build.json" },
{ "path": "../util/tsconfig.build.json" },
+20
View File
@@ -0,0 +1,20 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "..",
"outDir": "./build",
"rootDir": "./src",
"emitDeclarationOnly": false,
"noEmit": true
},
"include": [
"**/*.spec.ts"
],
"references": [
{ "path": "../networks/tsconfig.build.json" },
{ "path": "../util/tsconfig.build.json" },
{ "path": "../util-crypto/tsconfig.build.json" },
{ "path": "../x-bigint/tsconfig.build.json" },
{ "path": "../x-randomvalues/tsconfig.build.json" }
]
}
+7 -7
View File
@@ -18,7 +18,7 @@
"./detectPackage.cjs"
],
"type": "module",
"version": "12.1.2",
"version": "12.3.2",
"main": "index.js",
"exports": {
"./hex/toU8a": {
@@ -35,15 +35,15 @@
}
},
"dependencies": {
"@polkadot/x-bigint": "12.1.2",
"@polkadot/x-global": "12.1.2",
"@polkadot/x-textdecoder": "12.1.2",
"@polkadot/x-textencoder": "12.1.2",
"@polkadot/x-bigint": "12.3.2",
"@polkadot/x-global": "12.3.2",
"@polkadot/x-textdecoder": "12.3.2",
"@polkadot/x-textencoder": "12.3.2",
"@types/bn.js": "^5.1.1",
"bn.js": "^5.2.1",
"tslib": "^2.5.0"
"tslib": "^2.5.3"
},
"devDependencies": {
"@polkadot/x-randomvalues": "12.1.2"
"@polkadot/x-randomvalues": "12.3.2"
}
}
+7 -5
View File
@@ -19,28 +19,30 @@
* ```
*/
export function arrayFlatten <T> (arrays: readonly T[][]): T[] {
const num = arrays.length;
// shortcuts for the empty & single-entry case
if (arrays.length === 0) {
if (num === 0) {
return [];
} else if (arrays.length === 1) {
} else if (num === 1) {
return arrays[0];
}
// pre-allocate based on the combined size
let size = 0;
for (let i = 0; i < arrays.length; i++) {
for (let i = 0; i < num; i++) {
size += arrays[i].length;
}
const output = new Array<T>(size);
let i = -1;
for (let j = 0; j < arrays.length; j++) {
for (let j = 0; j < num; j++) {
const a = arrays[j];
// instead of pushing, we just set the entries
for (let e = 0; e < a.length; e++) {
for (let e = 0, count = a.length; e < count; e++) {
output[++i] = a[e];
}
}
+2 -2
View File
@@ -12,13 +12,13 @@ describe('arrayRange', (): void => {
).toThrow(/Expected non-zero, positive number as a range size/);
});
it('it creates a range of the specified length', (): void => {
it('creates a range of the specified length', (): void => {
expect(
arrayRange(10)
).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
});
it('it creates a range of the specified length, with offset', (): void => {
it('creates a range of the specified length, with offset', (): void => {
expect(
arrayRange(7, 3)
).toEqual([3, 4, 5, 6, 7, 8, 9]);
+4 -2
View File
@@ -4,13 +4,15 @@
/** @internal */
export function createCmp <T> (cmp: (a: T, b: T) => boolean): (...items: T[]) => T {
return (...items: T[]): T => {
if (items.length === 0) {
const count = items.length;
if (count === 0) {
throw new Error('Must provide one or more arguments');
}
let result = items[0];
for (let i = 1; i < items.length; i++) {
for (let i = 1; i < count; i++) {
if (cmp(items[i], result)) {
result = items[i];
}
+2 -2
View File
@@ -6,13 +6,13 @@
import { nMax } from './index.js';
describe('nMax', (): void => {
it('finds maximum', (): void => {
it('finds maximum (sorted)', (): void => {
expect(
nMax(1n, 2n, 3n)
).toEqual(3n);
});
it('finds maximum', (): void => {
it('finds maximum (unsorted)', (): void => {
expect(
nMax(2n, 3n, 1n)
).toEqual(3n);
+1
View File
@@ -6,6 +6,7 @@
import { BN } from '../bn/index.js';
import { _sqrt2pow53n, nSqrt } from './index.js';
// eslint-disable-next-line jest/no-export
export const SQRT_TESTS: [string | number | BN | bigint, string | number][] = [
[0, 0],
[1, 1],
+2 -2
View File
@@ -6,13 +6,13 @@
import { BN, bnMax } from './index.js';
describe('bnMax', (): void => {
it('finds BN maximum', (): void => {
it('finds BN maximum (sorted)', (): void => {
expect(
bnMax(new BN(1), new BN(2), new BN(3))
).toEqual(new BN(3));
});
it('finds BN maximum', (): void => {
it('finds BN maximum (unsorted)', (): void => {
expect(
bnMax(new BN(2), new BN(3), new BN(1))
).toEqual(new BN(3));
+1 -1
View File
@@ -95,7 +95,7 @@ describe('bnToU8a', (): void => {
).toEqual(new Uint8Array([46, 251, 255, 255]));
});
it('converts negative numbers (LE, bitLength)', (): void => {
it('converts negative numbers (LE, bitLength, check)', (): void => {
expect(
bnToU8a(new BN(-123456), { bitLength: 32, isNegative: true })
).toEqual(new Uint8Array([192, 29, 254, 255]));
+2 -2
View File
@@ -31,7 +31,7 @@ describe('compactFromU8a', (): void => {
);
});
it('decodes from same u32 encoded value (short)', (): void => {
it('decodes from same u32 encoded value (short, max)', (): void => {
expect(
compactFromU8a(new Uint8Array([254, 255, 255, 255])).toString()
).toEqual(
@@ -67,7 +67,7 @@ describe('compactFromU8a', (): void => {
).toEqual([7, new BN('5af3107a4000', 16)]);
});
it('decodes an actual value', (): void => {
it('decodes an actual value (100000000)', (): void => {
expect(
compactFromU8a(
hexToU8a('0x0284d717')
+13 -1
View File
@@ -6,6 +6,9 @@
import { u8aToHex } from '../u8a/index.js';
import { floatToU8a } from './index.js';
// NOTE Hex value outputs created via online conversion tool:
// https://www.h-schmidt.net/FloatConverter/IEEE754.html
describe('floatToU8a', (): void => {
it('throws on invalid bitLength', (): void => {
expect(
@@ -56,11 +59,20 @@ describe('floatToU8a', (): void => {
foo = 'bar';
}
// https://www.h-schmidt.net/FloatConverter/IEEE754.html
expect(
u8aToHex(floatToU8a(new Test(123.456)))
).toEqual('0x79e9f642');
});
it('encodes String 123.456', (): void => {
class Test extends String {
foo = 'bar';
}
expect(
u8aToHex(floatToU8a(new Test('123.456')))
).toEqual('0x79e9f642');
});
});
});
+2 -4
View File
@@ -1,9 +1,6 @@
// Copyright 2017-2023 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
// eslint-disable-next-line @typescript-eslint/ban-types
type AnyFloat = number | Number;
interface Options {
bitLength?: 32 | 64;
isLe?: boolean;
@@ -14,7 +11,8 @@ interface Options {
* @description Converts a float into a U8a representation (While we don't use BE in SCALE
* we still allow for either representation, although, as elsewhere, isLe is default)
*/
export function floatToU8a (value: string | AnyFloat = 0.0, { bitLength = 32, isLe = true }: Options = {}): Uint8Array {
// eslint-disable-next-line @typescript-eslint/ban-types
export function floatToU8a (value: String | string | number | Number = 0.0, { bitLength = 32, isLe = true }: Options = {}): Uint8Array {
if (bitLength !== 32 && bitLength !== 64) {
throw new Error('Invalid bitLength provided, expected 32 or 64');
}
+1 -1
View File
@@ -31,7 +31,7 @@ export const SI: SiDef[] = [
/** @internal */
export function findSi (type: string): SiDef {
// use a loop here, better RN support (which doesn't have [].find)
for (let i = 0; i < SI.length; i++) {
for (let i = 0, count = SI.length; i < count; i++) {
if (SI[i].value === type) {
return SI[i];
}
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2023 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BufferObjConstructor } from './types.js';
import type { BufferObjClass } from './types.js';
import { BigInt } from '@polkadot/x-bigint';
import { xglobal } from '@polkadot/x-global';
@@ -32,7 +32,7 @@ export const hasWasm = typeof WebAssembly !== 'undefined';
// that some bundlers such as parcel would add (this is a check, not a use)
/** true if the environment has support for Buffer (typically Node.js) */
export const hasBuffer = typeof xglobal.Buffer === 'function' && typeof (xglobal.Buffer as unknown as BufferObjConstructor).isBuffer === 'function';
export const hasBuffer = typeof xglobal.Buffer === 'function' && typeof (xglobal.Buffer as unknown as BufferObjClass).isBuffer === 'function';
/** true if the environment has process available (typically Node.js) */
export const hasProcess = typeof xglobal.process === 'object';
-6
View File
@@ -68,12 +68,6 @@ describe('hexToU8a', (): void => {
).toEqual(new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]));
});
it.skip('fails when non-hex value provided', (): void => {
expect(
() => hexToU8a('notahex')
).toThrow(/hex value to convert/);
});
perfCmp('hexToU8a', ['hexToU8aBuffer', 'hexToU8a'], 40, [[ptest]], (s: string, isSecond) =>
isSecond
? hexToU8a(s)
+1 -1
View File
@@ -7,7 +7,7 @@ const CHR = '0123456789abcdef';
const U8 = new Uint8Array(256);
const U16 = new Uint8Array(256 * 256);
for (let i = 0; i < CHR.length; i++) {
for (let i = 0, count = CHR.length; i < count; i++) {
U8[CHR[i].charCodeAt(0) | 0] = i | 0;
if (i > 9) {
@@ -35,10 +35,4 @@ describe('hexToU8a', (): void => {
new Uint8Array([128, 0])
);
});
it.skip('fails when non-hex value provided', (): void => {
expect(
() => hexToU8a('notahex')
).toThrow(/hex value to convert/);
});
});
+2 -6
View File
@@ -9,9 +9,7 @@ import { isString } from './string.js';
/** @internal */
function isAsciiStr (str: AnyString): boolean {
const count = str.length | 0;
for (let i = 0; i < count; i++) {
for (let i = 0, count = str.length; i < count; i++) {
const b = str.charCodeAt(i);
// check is inlined here, it is faster than making a call
@@ -25,9 +23,7 @@ function isAsciiStr (str: AnyString): boolean {
/** @internal */
function isAsciiBytes (u8a: Uint8Array | number[]): boolean {
const count = u8a.length | 0;
for (let i = 0; i < count; i++) {
for (let i = 0, count = u8a.length; i < count; i++) {
const b = u8a[i] | 0;
// check is inlined here, it is faster than making a call
+2 -2
View File
@@ -6,13 +6,13 @@
import { isBigInt } from './index.js';
describe('isBigInt', (): void => {
it('returns true when a BigInt value', (): void => {
it('returns true with a ...n value', (): void => {
expect(
isBigInt(123456n)
).toEqual(true);
});
it('returns true when a BigInt value', (): void => {
it('returns true with a BigInt(...) value', (): void => {
expect(
isBigInt(BigInt(123456))
).toEqual(true);
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2023 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BufferObj, BufferObjConstructor } from '../types.js';
import type { BufferObj, BufferObjClass } from '../types.js';
import { xglobal } from '@polkadot/x-global';
@@ -24,5 +24,5 @@ import { isFunction } from './function.js';
*/
export function isBuffer (value: unknown): value is Buffer {
// we do check a function first, since it is slightly faster than isBuffer itself
return hasBuffer && !!value && isFunction((value as unknown as BufferObj).readDoubleLE) && (xglobal.Buffer as unknown as BufferObjConstructor).isBuffer(value);
return hasBuffer && !!value && isFunction((value as unknown as BufferObj).readDoubleLE) && (xglobal.Buffer as unknown as BufferObjClass).isBuffer(value);
}
+4 -5
View File
@@ -28,10 +28,9 @@ describe('isChildClass', (): void => {
it('does TS magic, determining type', (): void => {
const T = (class extends BN {}) as unknown;
if (isChildClass(BN, T)) {
expect(new T(12345).toNumber()).toEqual(12345);
} else {
throw new Error('Not a child class');
}
expect(
isChildClass(BN, T) &&
new T(12345).toNumber()
).toEqual(12345);
});
});
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2023 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Constructor } from '../types.js';
import type { Class } from '../types.js';
import { isClass } from './class.js';
@@ -20,7 +20,7 @@ import { isClass } from './class.js';
* console.log('isChildClass', isChildClass(BN, Uint8Array); // => false
* ```
*/
export function isChildClass <P extends Constructor> (Parent: P, Child?: unknown): Child is P {
export function isChildClass <P extends Class> (Parent: P, Child?: unknown): Child is P {
// https://stackoverflow.com/questions/30993434/check-if-a-constructor-inherits-another-in-es6/30993664
return isClass(Child) && isClass(Parent)
// eslint-disable-next-line no-prototype-builtins
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2023 @polkadot/util authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Constructor } from '../types.js';
import type { Class } from '../types.js';
import { isOnFunction } from './helpers.js';
@@ -9,4 +9,4 @@ import { isOnFunction } from './helpers.js';
* @name isClass
* Tests if the supplied argument is a Class
*/
export const isClass: <T extends Constructor> (value?: unknown) => value is T = /*#__PURE__*/ isOnFunction('isPrototypeOf', 'hasOwnProperty');
export const isClass: <T extends Class> (value?: unknown) => value is T = /*#__PURE__*/ isOnFunction('isPrototypeOf', 'hasOwnProperty');
+1 -1
View File
@@ -26,7 +26,7 @@ describe('isUtf8', (): void => {
expect(isUtf8()).toEqual(false);
});
it('it is valid for ru', (): void => {
it('is valid for ru', (): void => {
expect(isUtf8('Приветствую, ми')).toEqual(true);
});
+11 -10
View File
@@ -7,7 +7,7 @@ import { lazyMethod, lazyMethods } from './index.js';
describe('lazyMethod', (): void => {
it('adds a key on the object', (): void => {
const test: Record<string, unknown> = {};
const test: { a?: number } = {};
expect(test.a).not.toBeDefined();
@@ -17,7 +17,7 @@ describe('lazyMethod', (): void => {
});
it('allows the name to be retrieved', (): void => {
const test: Record<string, unknown> = {};
const test: { a?: number } = {};
expect(test.a).not.toBeDefined();
@@ -27,7 +27,7 @@ describe('lazyMethod', (): void => {
});
it('calls the getter lazily', (): void => {
const test: Record<string, unknown> = {};
const test: { a?: number } = {};
const getter = jest.fn(() => 123);
expect(test.a).not.toBeDefined();
@@ -41,7 +41,7 @@ describe('lazyMethod', (): void => {
});
it('calls the getter a single time', (): void => {
const test: Record<string, unknown> = {};
const test: { a?: number } = {};
const getter = jest.fn(() => 123);
lazyMethod(test, 'a', getter);
@@ -56,15 +56,16 @@ describe('lazyMethod', (): void => {
describe('lazyMethods', (): void => {
it('sets multiple properties', (): void => {
const test: Record<string, unknown> = {};
const test: { a?: string; b?: string; c?: string } = {};
const getter = jest.fn((name: string) => name);
const set = lazyMethods(test, ['a', 'b', 'c'], getter);
expect(set.a).toEqual('a');
expect(set.b).toEqual('b');
lazyMethods(test, ['a', 'b', 'c'], getter);
expect(test.a).toEqual('a');
expect(test.b).toEqual('b');
expect(getter).toHaveBeenCalledTimes(2);
expect(set.a).toEqual('a');
expect(set.b).toEqual('b');
expect(test.a).toEqual('a');
expect(test.b).toEqual('b');
expect(getter).toHaveBeenCalledTimes(2);
});
});
+1 -1
View File
@@ -55,7 +55,7 @@ export function lazyMethod <T, K, S> (result: Record<string, T> | AnyFn, item: K
* Creates lazy, on-demand getters for the specific values.
*/
export function lazyMethods <T, K, S> (result: Record<string, T>, items: readonly K[], creator: (item: K, index: number, self: S) => T, getName?: (item: K, index: number) => string): Record<string, T> {
for (let i = 0; i < items.length; i++) {
for (let i = 0, count = items.length; i < count; i++) {
lazyMethod(result, items[i], creator, getName, i);
}
+8 -8
View File
@@ -18,11 +18,11 @@ describe('logger', (): void => {
beforeEach((): void => {
oldEnv = process.env;
process.env.NODE_ENV = 'development';
process.env['NODE_ENV'] = 'development';
ln = logger('notDebug');
process.env.DEBUG = 'test';
process.env['DEBUG'] = 'test';
l = logger('test');
@@ -114,7 +114,7 @@ describe('logger', (): void => {
});
it('does debug log when DEBUG partial specified', (): void => {
process.env.DEBUG = 'test*';
process.env['DEBUG'] = 'test*';
l = logger('testing');
l.debug('test');
@@ -127,7 +127,7 @@ describe('logger', (): void => {
});
it('does not debug log when non-matching DEBUG specified', (): void => {
process.env.DEBUG = 'blah';
process.env['DEBUG'] = 'blah';
l = logger('test');
l.debug('test');
@@ -136,7 +136,7 @@ describe('logger', (): void => {
});
it('does debug log when DEBUG=* specified', (): void => {
process.env.DEBUG = '*';
process.env['DEBUG'] = '*';
l = logger('test');
l.debug('test');
@@ -160,7 +160,7 @@ describe('logger', (): void => {
});
it('does not debug log when explicitly excluded', (): void => {
process.env.DEBUG = '*,-test';
process.env['DEBUG'] = '*,-test';
l = logger('test');
l.debug('test');
@@ -169,7 +169,7 @@ describe('logger', (): void => {
});
it('does not debug log when part of exclusion group', (): void => {
process.env.DEBUG = '*,-test:*';
process.env['DEBUG'] = '*,-test:*';
l = logger('test:sub');
l.debug('test');
@@ -178,7 +178,7 @@ describe('logger', (): void => {
});
it('does debug log when not part of exclusion groups', (): void => {
process.env.DEBUG = '*,-test:*,-tes,-a:*';
process.env['DEBUG'] = '*,-test:*,-tes,-a:*';
l = logger('test');
l.debug('test');
+2 -2
View File
@@ -122,10 +122,10 @@ function getDebugFlag (env: readonly string[], type: string): boolean {
function parseEnv (type: string): [boolean, number] {
const env = (hasProcess ? xglobal.process as { env: Record<string, string> } : {}).env || {};
const maxSize = parseInt(env.DEBUG_MAX || '-1', 10);
const maxSize = parseInt(env['DEBUG_MAX'] || '-1', 10);
return [
getDebugFlag((env.DEBUG || '').toLowerCase().split(','), type),
getDebugFlag((env['DEBUG'] || '').toLowerCase().split(','), type),
isNaN(maxSize)
? -1
: maxSize
+1 -1
View File
@@ -8,7 +8,7 @@
export function objectClear <T> (value: Record<string, T>): Record<string, T> {
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i++) {
for (let i = 0, count = keys.length; i < count; i++) {
delete value[keys[i]];
}
+7 -7
View File
@@ -8,7 +8,7 @@ import { objectProperties, objectProperty } from './index.js';
describe('objectProperty/objectProperties', (): void => {
it('sets a property', (): void => {
const test: Record<string, unknown> = {};
const test: { a?: unknown } = {};
expect(test.a).toEqual(undefined);
@@ -20,7 +20,7 @@ describe('objectProperty/objectProperties', (): void => {
});
it('does not override an existing property (record)', (): void => {
const test: Record<string, unknown> = { a: 1 };
const test = { a: 1 };
expect(test.a).toEqual(1);
@@ -75,7 +75,7 @@ describe('objectProperty/objectProperties', (): void => {
}
}
const test = new Child() as unknown as Record<string, unknown>;
const test = new Child() as unknown as { a: number; b: number; c?: number };
expect(test.a).toEqual(1);
expect(test.b).toEqual(1);
@@ -99,7 +99,7 @@ describe('objectProperty/objectProperties', (): void => {
}
}
const test = new Test() as unknown as Record<string, unknown>;
const test = new Test() as unknown as { a: number };
expect(test.a).toEqual(1);
});
@@ -116,14 +116,14 @@ describe('objectProperty/objectProperties', (): void => {
}
}
const test = new Test() as unknown as Record<string, unknown>;
const test = new Test() as unknown as { a: number; b: number };
expect(test.a).toEqual(1);
expect(test.b).toEqual(2);
});
it('calls back with the key name (single)', (): void => {
const test: Record<string, unknown> = {};
const test: { a?: number } = {};
const getter = jest.fn(() => 123);
objectProperty(test, 'a', getter);
@@ -134,7 +134,7 @@ describe('objectProperty/objectProperties', (): void => {
});
it('calls back with the key name & index (numtiple)', (): void => {
const test: Record<string, unknown> = {};
const test: { a?: number; b?: number; c?: number } = {};
const getter = jest.fn(() => 123);
objectProperties(test, ['a', 'b', 'c'], getter);
+1 -1
View File
@@ -33,7 +33,7 @@ export function objectProperty <S> (that: object, key: string, getter: (key: str
* @summary Assign get properties on the input object
*/
export function objectProperties <S> (that: object, keys: string[], getter: (key: string, index: number, self: S) => unknown, getName?: (key: string, index: number) => string): void {
for (let i = 0; i < keys.length; i++) {
for (let i = 0, count = keys.length; i < count; i++) {
objectProperty(that, keys[i], getter, getName, i);
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
* @summary Concats all sources into the destination
*/
export function objectSpread <T extends object> (dest: object, ...sources: (object | undefined | null)[]): T {
for (let i = 0; i < sources.length; i++) {
for (let i = 0, count = sources.length; i < count; i++) {
const src = sources[i];
if (src) {
+1 -1
View File
@@ -3,4 +3,4 @@
// Do not edit, auto-generated by @polkadot/dev
export const packageInfo = { name: '@polkadot/util', path: 'auto', type: 'auto', version: '12.1.2' };
export const packageInfo = { name: '@polkadot/util', path: 'auto', type: 'auto', version: '12.3.2' };
+2
View File
@@ -24,6 +24,7 @@ describe('promisify', (): void => {
throw new Error('Received unexpected result');
})
.catch((error: Error): void => {
// eslint-disable-next-line jest/no-conditional-expect
expect(error.message).toEqual('test reject');
});
});
@@ -42,6 +43,7 @@ describe('promisify', (): void => {
cb(new Error(`test reject: ${a},${b.toString()},${c}`));
return promisify(null, fn, 3, 'string', true).catch((error: Error): void => {
// eslint-disable-next-line jest/no-conditional-expect
expect(error.message).toEqual('test reject: 3,string,true');
});
});
+1 -1
View File
@@ -17,7 +17,7 @@
* ```
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function promisify <R = any> (self: unknown, fn: (...params: any) => any, ...params: any[]): Promise<R> {
export function promisify <R = any> (self: unknown, fn: (...params: any[]) => any, ...params: any[]): Promise<R> {
return new Promise((resolve, reject): void => {
fn.apply(self, params.concat((error: Error | null, result?: R): void => {
if (error) {
+2 -3
View File
@@ -6,7 +6,7 @@ import type { AnyString } from '../types.js';
export const CC_TO_UP = new Array<string>(256);
export const CC_TO_LO = new Array<string>(256);
for (let i = 0; i < CC_TO_UP.length; i++) {
for (let i = 0, count = CC_TO_UP.length; i < count; i++) {
CC_TO_LO[i] = String.fromCharCode(i).toLowerCase();
CC_TO_UP[i] = String.fromCharCode(i).toUpperCase();
}
@@ -39,10 +39,9 @@ function converter (format: (w: string, i: number) => string): (value: AnyString
.trim()
// split into words
.split(' ');
const count = parts.length;
let result = '';
for (let i = 0; i < count; i++) {
for (let i = 0, count = parts.length; i < count; i++) {
const w = parts[i];
// apply the formatting
+4 -2
View File
@@ -3,6 +3,8 @@
/// <reference types="@polkadot/dev-test/globals.d.ts" />
/* global it, expect */
import { formatDecimal, formatNumber } from '../index.js';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -42,7 +44,7 @@ ${formatFixed(micro).padStart(NUM_PAD + PRE_PAD + 1)} μs/op`;
}
export function perf (name: string, count: number, inputs: readonly unknown[][], exec: ExecFn, withLog?: boolean): void {
const test = process.env.GITHUB_REPOSITORY
const test = process.env['GITHUB_REPOSITORY']
? it.skip
: it;
@@ -62,7 +64,7 @@ ${`${name}:`.padStart(PRE_PAD)} ${time.toFixed(2).padStart(NUM_PAD)} ms${formatO
}
export function perfCmp (name: string, [first, second]: [string, string], count: number, inputs: readonly unknown[][], exec: ExecFn): void {
const test = process.env.GITHUB_REPOSITORY
const test = process.env['GITHUB_REPOSITORY']
? it.skip
: it;
+11 -6
View File
@@ -3,15 +3,20 @@
import type { BN } from './bn/bn.js';
export interface Constructor<T extends object = object> {
/* eslint-disable @typescript-eslint/no-explicit-any */
export interface Class<T = any, A extends unknown[] = any[]> {
prototype: T;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
new (...args: any[]): T;
new (...args: A): T;
hasOwnProperty (prop: string): boolean;
isPrototypeOf (other: unknown): boolean;
}
// @deprecated Use Class<T, A> instead
export type Constructor<T = any, A extends unknown[] = any[]> = Class<T, A>;
export interface ToBigInt {
toBigInt: () => bigint;
}
@@ -75,13 +80,13 @@ export type HexString = `0x${string}`;
// BufferObj interface compatible with Buffer since we don't want to require
// references to the Buffer types from the node typings
export interface BufferObj extends Uint8Array {
equals (otherBuffer: Uint8Array): boolean;
readDoubleLE (offset?: number): number;
equals: (otherBuffer: Uint8Array) => boolean;
readDoubleLE: (offset?: number) => number;
}
// We define a scappy low-level interface to mock Buffer
// (this removes the need for the node typings in built bundles)
export interface BufferObjConstructor extends Constructor<BufferObj> {
export interface BufferObjClass extends Class<BufferObj> {
isBuffer: (value: unknown) => boolean;
}
+1 -1
View File
@@ -10,7 +10,7 @@ const ltest = new Uint8Array(32768);
const stest = new Uint8Array(256);
const ztest = new Uint8Array(64);
for (let i = 0; i < ltest.length; i++) {
for (let i = 0, count = ltest.length; i < count; i++) {
if (i < ztest.length) {
ztest[i] = i % 256;
}
+3 -2
View File
@@ -40,17 +40,18 @@ export function u8aConcat (...list: readonly U8aLike[]): Uint8Array {
* @description A strict version of [[u8aConcat]], accepting only Uint8Array inputs
*/
export function u8aConcatStrict (u8as: readonly Uint8Array[], length = 0): Uint8Array {
const count = u8as.length;
let offset = 0;
if (!length) {
for (let i = 0; i < u8as.length; i++) {
for (let i = 0; i < count; i++) {
length += u8as[i].length;
}
}
const result = new Uint8Array(length);
for (let i = 0; i < u8as.length; i++) {
for (let i = 0; i < count; i++) {
result.set(u8as[i], offset);
offset += u8as[i].length;
}
+2 -2
View File
@@ -10,7 +10,7 @@ const ltest = new Uint8Array(32768);
const stest = new Uint8Array(256);
const ztest = new Uint8Array(64);
for (let i = 0; i < ltest.length; i++) {
for (let i = 0, count = ltest.length; i < count; i++) {
if (i < ztest.length) {
ztest[i] = i % 256;
}
@@ -98,7 +98,7 @@ describe('u8aEq', (): void => {
it('works on aubarray values', (): void => {
const a = new Uint8Array(16);
for (let i = 0; i < a.length; i++) {
for (let i = 0, count = a.length; i < count; i++) {
a[i] = i;
}
+1 -1
View File
@@ -35,7 +35,7 @@ export function u8aEq (a: HexString | Uint8Array | string, b: HexString | Uint8A
}
}
for (let i = length; i < u8aa.length; i++) {
for (let i = length, count = u8aa.length; i < count; i++) {
if (u8aa[i] !== u8ab[i]) {
return false;
}
+60 -3
View File
@@ -54,6 +54,15 @@ describe('u8aToBigInt', (): void => {
).toBe('78563412');
});
it('converts values (i32)', (): void => {
expect(
u8aToBigInt(
new Uint8Array([0xf2, 0x34, 0x56, 0x78]),
{ isLe: false, isNegative: true }
).toString(16)
).toBe('-dcba988');
});
it('converts values (u40)', (): void => {
expect(
u8aToBigInt(
@@ -71,6 +80,29 @@ describe('u8aToBigInt', (): void => {
).toString(16)
).toBe('bc9a78563412');
});
it('converts values (u128)', (): void => {
expect(
u8aToBigInt(
new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]),
{ isLe: true }
).toString(16)
).toBe('78563412785634127856341278563412');
});
for (let i = 1; i < 32; i++) {
const tu8a = [0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78];
const tstr = tu8a.map((n) => n.toString(16));
it(`converts values with length ${i}`, (): void => {
expect(
u8aToBigInt(
new Uint8Array(tu8a.slice(0, i)),
{ isLe: true }
).toString(16)
).toBe(tstr.slice(0, i).reverse().join(''));
});
}
});
describe('signed', (): void => {
@@ -193,6 +225,29 @@ describe('u8aToBigInt', (): void => {
).toString(16)
).toBe('123456789abc');
});
it('converts values (u128)', (): void => {
expect(
u8aToBigInt(
new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]),
{ isLe: false }
).toString(16)
).toBe('12345678123456781234567812345678');
});
for (let i = 1; i < 32; i++) {
const tu8a = [0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78];
const tstr = tu8a.map((n) => n.toString(16));
it(`converts values with length ${i}`, (): void => {
expect(
u8aToBigInt(
new Uint8Array(tu8a.slice(0, i)),
{ isLe: false }
).toString(16)
).toBe(tstr.slice(0, i).join(''));
});
}
});
describe('empty creation', (): void => {
@@ -262,9 +317,11 @@ describe('u8aToBigInt', (): void => {
).toBe(256n);
});
perf('u8aToBigInt (u32)', 1_000_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
perf('u8aToBigInt (i32)', 1_000_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], (v: Uint8Array) => u8aToBigInt(v, { isNegative: true }));
perf('u8aToBigInt (u64)', 500_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
perf('u8aToBigInt (i32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], (v: Uint8Array) => u8aToBigInt(v, { isNegative: true }));
perf('u8aToBigInt (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
perf('u8aToBigInt (u64)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
perf('u8aToBigInt (u128)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBigInt);
// perf('BigInt (constructor)', 1_000_000, [[12345678]], (v: number) => BigInt(v).toString());
// perf('BigInt (constructor -> string)', 1_000_000, [[12345678]], (v: number) => BigInt(v).toString());
+65 -20
View File
@@ -9,27 +9,43 @@ import { _1n } from '../bi/consts.js';
const U8_MAX = BigInt(256);
const U16_MAX = BigInt(256 * 256);
const U64_MAX = BigInt('0x10000000000000000');
/**
* @name u8aToBigInt
* @summary Creates a BigInt from a Uint8Array object.
*/
export function u8aToBigInt (value: Uint8Array, { isLe = true, isNegative = false }: ToBnOptions = {}): bigint {
if (!value || !value.length) {
return BigInt(0);
}
// BE is not the optimal path - LE is the SCALE default
const u8a = isLe
? value
: value.reverse();
const dvI = new DataView(u8a.buffer, u8a.byteOffset);
: value.slice().reverse();
const count = u8a.length;
const mod = count % 2;
let result = BigInt(0);
// This is mostly written for readability (with the single isNegative shortcut),
// as opposed to performance, e.g. `u8aToBn` does loop unrolling, etc.
if (isNegative) {
switch (count) {
case 0:
return BigInt(0);
case 1:
return BigInt(((u8a[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
return BigInt((((u8a[0] + (u8a[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 4:
return BigInt((((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
}
const dvI = new DataView(u8a.buffer, u8a.byteOffset);
if (count === 8) {
return dvI.getBigInt64(0, true);
}
let result = BigInt(0);
const mod = count % 2;
for (let i = count - 2; i >= mod; i -= 2) {
result = (result * U16_MAX) + BigInt(dvI.getUint16(i, true) ^ 0xffff);
}
@@ -37,17 +53,46 @@ export function u8aToBigInt (value: Uint8Array, { isLe = true, isNegative = fals
if (mod) {
result = (result * U8_MAX) + BigInt(u8a[0] ^ 0xff);
}
} else {
for (let i = count - 2; i >= mod; i -= 2) {
result = (result * U16_MAX) + BigInt(dvI.getUint16(i, true));
}
if (mod) {
result = (result * U8_MAX) + BigInt(u8a[0]);
}
return (result * -_1n) - _1n;
}
return isNegative
? ((result * -_1n) - _1n)
: result;
switch (count) {
case 0:
return BigInt(0);
case 1:
return BigInt(u8a[0]);
case 2:
return BigInt(u8a[0] + (u8a[1] << 8));
case 4:
return BigInt(u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 0x1_00_00_00));
}
const dvI = new DataView(u8a.buffer, u8a.byteOffset);
switch (count) {
case 8:
return dvI.getBigUint64(0, true);
case 16:
return (dvI.getBigUint64(8, true) * U64_MAX) + dvI.getBigUint64(0, true);
default: {
let result = BigInt(0);
const mod = count % 2;
for (let i = count - 2; i >= mod; i -= 2) {
result = (result * U16_MAX) + BigInt(dvI.getUint16(i, true));
}
if (mod) {
result = (result * U8_MAX) + BigInt(u8a[0]);
}
return result;
}
}
}
+60 -3
View File
@@ -72,6 +72,29 @@ describe('u8aToBn', (): void => {
).toString(16)
).toBe('bc9a78563412');
});
it('converts values (u128)', (): void => {
expect(
u8aToBn(
new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]),
{ isLe: true }
).toString(16)
).toBe('78563412785634127856341278563412');
});
for (let i = 1; i < 32; i++) {
const tu8a = [0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78];
const tstr = tu8a.map((n) => n.toString(16));
it(`converts values with length ${i}`, (): void => {
expect(
u8aToBn(
new Uint8Array(tu8a.slice(0, i)),
{ isLe: true }
).toString(16)
).toBe(tstr.slice(0, i).reverse().join(''));
});
}
});
describe('signed', (): void => {
@@ -177,6 +200,15 @@ describe('u8aToBn', (): void => {
).toBe('12345678');
});
it('converts values (i32)', (): void => {
expect(
u8aToBn(
new Uint8Array([0xf2, 0x34, 0x56, 0x78]),
{ isLe: false, isNegative: true }
).toString(16)
).toBe('-dcba988');
});
it('converts values (u40)', (): void => {
expect(
u8aToBn(
@@ -194,6 +226,29 @@ describe('u8aToBn', (): void => {
).toString(16)
).toBe('123456789abc');
});
it('converts values (u128)', (): void => {
expect(
u8aToBn(
new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]),
{ isLe: false }
).toString(16)
).toBe('12345678123456781234567812345678');
});
for (let i = 1; i < 32; i++) {
const tu8a = [0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78];
const tstr = tu8a.map((n) => n.toString(16));
it(`converts values with length ${i}`, (): void => {
expect(
u8aToBn(
new Uint8Array(tu8a.slice(0, i)),
{ isLe: false }
).toString(16)
).toBe(tstr.slice(0, i).join(''));
});
}
});
describe('empty creation', (): void => {
@@ -263,9 +318,11 @@ describe('u8aToBn', (): void => {
).toBe(256);
});
perf('u8aToBn (u32)', 1_000_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
perf('u8aToBn (i32)', 1_000_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], (v: Uint8Array) => u8aToBn(v, { isNegative: true }));
perf('u8aToBn (u64)', 500_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
perf('u8aToBn (i32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], (v: Uint8Array) => u8aToBn(v, { isNegative: true }));
perf('u8aToBn (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
perf('u8aToBn (u64)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
perf('u8aToBn (u128)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c, 0x68, 0x65, 0x6c, 0x6c])]], u8aToBn);
// perf('BN (constructor)', 1_000_000, [[12345678]], (v: number) => new BN(v));
// perf('BN (constructor -> string)', 1_000_000, [[12345678]], (v: number) => new BN(v).toString());
+74 -69
View File
@@ -28,95 +28,100 @@ export function u8aToBn (value: Uint8Array, { isLe = true, isNegative = false }:
// shortcut for <= u48 values - in this case the manual conversion
// here seems to be more efficient than passing the full array
if (count <= 6) {
if (isNegative) {
let result = 0;
if (isLe) {
// Most common case i{8, 16, 32} default LE SCALE-encoded
// For <= 32, we also optimize the xor to a single op
// (see the comments around unrolling in the next section)
switch (count) {
case 0:
return new BN(0);
case 1:
result = value[0] ^ 0x0000_00ff;
break;
case 2:
result = (value[0] + (value[1] << 8)) ^ 0x0000_ffff;
break;
case 3:
result = (value[0] + (value[1] << 8) + (value[2] << 16)) ^ 0x00ff_ffff;
break;
case 4:
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
// 32-bit, in the case where the top-most bit is set this yields a negative value
result = (value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff;
break;
case 5:
result = ((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((value[4] ^ 0xff) * 0x1_00_00_00_00);
break;
default: // 6
result = ((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((value[4] + (value[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00);
break;
}
} else {
for (let i = 0; i < count; i++) {
result = (result * 0x1_00) + (value[i] ^ 0xff);
}
}
return count
? new BN((result * -1) - 1)
: new BN(0);
} else if (isLe) {
// Most common case - u{8, 16, 32} default LE SCALE-encoded
//
// There are some slight benefits in unrolling this specific loop,
// however it comes with diminishing returns since here the actual
// `new BN` does seem to take up the bulk of the time
if (isNegative) {
if (isLe) {
// Most common case i{8, 16, 32} default LE SCALE-encoded
// For <= 32, we also optimize the xor to a single op
switch (count) {
case 0:
return new BN(0);
case 1:
return new BN(value[0]);
return new BN(((value[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
return new BN(value[0] + (value[1] << 8));
return new BN((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 3:
return new BN(value[0] + (value[1] << 8) + (value[2] << 16));
return new BN((((value[0] + (value[1] << 8) + (value[2] << 16)) ^ 0x00ff_ffff) * -1) - 1);
case 4:
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
// 32-bit, in the case where the top-most bit is set this yields a negative value
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00));
return new BN((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
case 5:
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8)) * 0x1_00_00_00));
return new BN(((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((value[4] ^ 0xff) * 0x1_00_00_00_00)) * -1) - 1);
default: // 6
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8) + (value[5] << 16)) * 0x1_00_00_00));
case 6:
return new BN(((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((value[4] + (value[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00)) * -1) - 1);
default:
return new BN(value, 'le').fromTwos(value.length * 8);
}
} else {
let result = 0;
}
for (let i = 0; i < count; i++) {
result = (result * 0x1_00) + value[i];
}
if (count === 0) {
return new BN(0);
} else if (count > 6) {
return new BN(value, 'be').fromTwos(value.length * 8);
}
return new BN(result);
let result = 0;
for (let i = 0; i < count; i++) {
result = (result * 0x1_00) + (value[i] ^ 0xff);
}
return new BN((result * -1) - 1);
}
if (isLe) {
// Most common case - u{8, 16, 32} default LE SCALE-encoded
//
// There are some slight benefits in unrolling this specific loop,
// however it comes with diminishing returns since here the actual
// `new BN` does seem to take up the bulk of the time
switch (count) {
case 0:
return new BN(0);
case 1:
return new BN(value[0]);
case 2:
return new BN(value[0] + (value[1] << 8));
case 3:
return new BN(value[0] + (value[1] << 8) + (value[2] << 16));
case 4:
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
// 32-bit, in the case where the top-most bit is set this yields a negative value
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00));
case 5:
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8)) * 0x1_00_00_00));
case 6:
return new BN(value[0] + (value[1] << 8) + (value[2] << 16) + ((value[3] + (value[4] << 8) + (value[5] << 16)) * 0x1_00_00_00));
default:
return new BN(value, 'le');
}
}
return isNegative
? new BN(value, isLe ? 'le' : 'be').fromTwos(value.length * 8)
: new BN(value, isLe ? 'le' : 'be');
if (count === 0) {
return new BN(0);
} else if (count > 6) {
return new BN(value, 'be');
}
let result = 0;
for (let i = 0; i < count; i++) {
result = (result * 0x1_00) + value[i];
}
return new BN(result);
}
+1 -1
View File
@@ -10,7 +10,7 @@ import { u8aToHex as u8aToHexBuffer } from './toHexBuffer.js';
const ptest32k = new Uint8Array(32768);
const ptest256 = new Uint8Array(256);
for (let i = 0; i < ptest32k.length; i++) {
for (let i = 0, count = ptest32k.length; i < count; i++) {
if (i < ptest256.length) {
ptest256[1] = i % 256;
}
+2 -2
View File
@@ -132,6 +132,6 @@ describe('u8aToNumber', (): void => {
});
});
perf('u8aToNumber (u32)', 1_000_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToNumber);
perf('u8aToNumber (i32)', 1_000_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], (v: Uint8Array) => u8aToNumber(v, { isNegative: true }));
perf('u8aToNumber (i32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], (v: Uint8Array) => u8aToNumber(v, { isNegative: true }));
perf('u8aToNumber (u32)', 750_000, [[new Uint8Array([0x68, 0x65, 0x6c, 0x6c])]], u8aToNumber);
});
+7 -17
View File
@@ -10,49 +10,39 @@ interface ToNumberOptions {
/**
* @name u8aToNumber
* @summary Creates a number from a Uint8Array object.
* @summary Creates a number from a Uint8Array object. This only operates on LE values as used in SCALE.
*/
export function u8aToNumber (value: Uint8Array, { isNegative = false }: ToNumberOptions = {}): number {
const count = value.length;
if (isNegative) {
let result = 0;
switch (count) {
case 0:
return 0;
case 1:
result = value[0] ^ 0x0000_00ff;
break;
return (((value[0] ^ 0x0000_00ff) * -1) - 1);
case 2:
result = (value[0] + (value[1] << 8)) ^ 0x0000_ffff;
break;
return ((((value[0] + (value[1] << 8)) ^ 0x0000_ffff) * -1) - 1);
case 3:
result = (value[0] + (value[1] << 8) + (value[2] << 16)) ^ 0x00ff_ffff;
break;
return ((((value[0] + (value[1] << 8) + (value[2] << 16)) ^ 0x00ff_ffff) * -1) - 1);
case 4:
// for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
// 32-bit, in the case where the top-most bit is set this yields a negative value
result = (value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff;
break;
return ((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) * -1) - 1);
case 5:
result = ((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((value[4] ^ 0xff) * 0x1_00_00_00_00);
break;
return (((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + ((value[4] ^ 0xff) * 0x1_00_00_00_00)) * -1) - 1);
case 6:
result = ((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((value[4] + (value[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00);
break;
return (((((value[0] + (value[1] << 8) + (value[2] << 16) + (value[3] * 0x1_00_00_00)) ^ 0xffff_ffff) + (((value[4] + (value[5] << 8)) ^ 0x0000_ffff) * 0x1_00_00_00_00)) * -1) - 1);
default:
throw new Error('Value more than 48-bits cannot be reliably converted');
}
return (result * -1) - 1;
}
switch (count) {
+2 -2
View File
@@ -18,7 +18,7 @@ describe('u8aToString', (): void => {
).toEqual('');
});
it('decodes the Uint8Array correctly', (): void => {
it('decodes the Uint8Array correctly (ru)', (): void => {
expect(
u8aToString(
new Uint8Array([208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130, 44, 32, 208, 188, 208, 184, 209, 128, 33])
@@ -26,7 +26,7 @@ describe('u8aToString', (): void => {
).toEqual('Привет, мир!');
});
it('decodes the Uint8Array correctly', (): void => {
it('decodes the Uint8Array correctly (en)', (): void => {
expect(
u8aToString(
new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64])
+4
View File
@@ -5,6 +5,10 @@
"outDir": "./build",
"rootDir": "./src"
},
"exclude": [
"**/*.spec.ts",
"**/mod.ts"
],
"references": [
{ "path": "../x-bigint/tsconfig.build.json" },
{ "path": "../x-global/tsconfig.build.json" },

Some files were not shown because too many files have changed in this diff Show More