Adjust base library usage of for vs reduce/map (#1151)
* Adjust base library usage of `for` vs `reduce/map` * Additional * Adjust
This commit is contained in:
@@ -10,6 +10,7 @@ Changes:
|
||||
|
||||
- Add `arrayZip` to combine a key + value array into entries-like
|
||||
- Assert `chainCode` inputs to `derive*`, protecting against misuse
|
||||
- Adjust base library usage of `for` vs `reduce/map`
|
||||
- Adjust testnet detection in `@polkadot/networks`
|
||||
- Bump Ledger libraries to latest versions
|
||||
|
||||
|
||||
@@ -262,11 +262,7 @@ export class Keyring implements KeyringInstance {
|
||||
* @description Returns an array list of all the public keys associated with each of the keyring pair values that are stored in the keyring pair dictionary.
|
||||
*/
|
||||
public getPublicKeys (): Uint8Array[] {
|
||||
return this.#pairs
|
||||
.all()
|
||||
.map(({ publicKey }): Uint8Array =>
|
||||
publicKey
|
||||
);
|
||||
return this.#pairs.all().map(({ publicKey }) => publicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -121,7 +121,7 @@ export function createTestKeyring (options: KeyringOptions = {}, isDerived = tru
|
||||
const keyring = new Keyring(options);
|
||||
const pairs: PairDef[] = (options.type && options.type === 'ethereum') ? PAIRSETHEREUM : PAIRSSR25519;
|
||||
|
||||
pairs.forEach(({ name, publicKey, secretKey, seed, type }): void => {
|
||||
for (const { name, publicKey, secretKey, seed, type } of pairs) {
|
||||
if (!name && !seed) {
|
||||
throw new Error('Testing pair should have either a name or a seed');
|
||||
}
|
||||
@@ -139,7 +139,7 @@ export function createTestKeyring (options: KeyringOptions = {}, isDerived = tru
|
||||
pair.lock = (): void => {
|
||||
// we don't have lock/unlock functionality here
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return keyring;
|
||||
}
|
||||
|
||||
@@ -15,11 +15,9 @@ export function createTestPairs (options?: KeyringOptions, isDerived = true): Te
|
||||
const pairs = keyring.getPairs();
|
||||
const map: TestKeyringMap = { nobody: nobody() };
|
||||
|
||||
return pairs.reduce((result, pair): TestKeyringMap => {
|
||||
const { name } = pair.meta;
|
||||
for (const p of pairs) {
|
||||
map[p.meta.name as string] = p;
|
||||
}
|
||||
|
||||
result[name as string] = pair;
|
||||
|
||||
return result;
|
||||
}, map);
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { Prefix } from './types';
|
||||
import { assert } from '@polkadot/util';
|
||||
|
||||
import { keyExtractPath } from '../key';
|
||||
import { DeriveJunction } from '../key/DeriveJunction';
|
||||
import { schnorrkelDerivePublic } from '../schnorrkel';
|
||||
import { decodeAddress } from './decode';
|
||||
import { encodeAddress } from './encode';
|
||||
@@ -21,9 +20,13 @@ import { encodeAddress } from './encode';
|
||||
export function deriveAddress (who: HexString | Uint8Array | string, suri: string, ss58Format?: Prefix): string {
|
||||
const { path } = keyExtractPath(suri);
|
||||
|
||||
assert(path.length && !path.some((path) => path.isHard), 'Expected suri to contain a combination of non-hard paths');
|
||||
assert(path.length && !path.some((p) => p.isHard), 'Expected suri to contain a combination of non-hard paths');
|
||||
|
||||
return encodeAddress(path.reduce((publicKey: Uint8Array, path: DeriveJunction): Uint8Array => {
|
||||
return schnorrkelDerivePublic(publicKey, path.chainCode);
|
||||
}, decodeAddress(who)), ss58Format);
|
||||
let publicKey = decodeAddress(who);
|
||||
|
||||
for (const { chainCode } of path) {
|
||||
publicKey = schnorrkelDerivePublic(publicKey, chainCode);
|
||||
}
|
||||
|
||||
return encodeAddress(publicKey, ss58Format);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ function deriveChild (hd: CodedKeypair, index: number): CodedKeypair {
|
||||
|
||||
export function hdEthereum (seed: Uint8Array, path = ''): Keypair {
|
||||
const I = hmacSha512(MASTER_SECRET, seed);
|
||||
const hd = createCoded(I.slice(0, 32), I.slice(32));
|
||||
let hd = createCoded(I.slice(0, 32), I.slice(32));
|
||||
|
||||
if (!path || path === 'm' || path === 'M' || path === "m'" || path === "M'") {
|
||||
return hd;
|
||||
@@ -52,16 +52,15 @@ export function hdEthereum (seed: Uint8Array, path = ''): Keypair {
|
||||
|
||||
assert(hdValidatePath(path), 'Invalid derivation path');
|
||||
|
||||
return path
|
||||
.split('/')
|
||||
.slice(1)
|
||||
.reduce((hd: CodedKeypair, c): CodedKeypair =>
|
||||
deriveChild(
|
||||
hd, parseInt(c, 10) + (
|
||||
(c.length > 1) && c.endsWith("'")
|
||||
? HARDENED
|
||||
: 0
|
||||
)
|
||||
), hd
|
||||
);
|
||||
const parts = path.split('/').slice(1);
|
||||
|
||||
for (const p of parts) {
|
||||
hd = deriveChild(hd, parseInt(p, 10) + (
|
||||
(p.length > 1) && p.endsWith("'")
|
||||
? HARDENED
|
||||
: 0
|
||||
));
|
||||
}
|
||||
|
||||
return hd;
|
||||
}
|
||||
|
||||
@@ -12,27 +12,28 @@ import { ledgerDerivePrivate } from './derivePrivate';
|
||||
import { ledgerMaster } from './master';
|
||||
|
||||
export function hdLedger (_mnemonic: string, path: string): Keypair {
|
||||
const parts = _mnemonic
|
||||
const words = _mnemonic
|
||||
.split(' ')
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s);
|
||||
|
||||
assert([12, 24, 25].includes(parts.length), 'Expected a mnemonic with 24 words (or 25 including a password)');
|
||||
assert([12, 24, 25].includes(words.length), 'Expected a mnemonic with 24 words (or 25 including a password)');
|
||||
|
||||
const [mnemonic, password] = parts.length === 25
|
||||
? [parts.slice(0, 24).join(' '), parts[24]]
|
||||
: [parts.join(' '), ''];
|
||||
const [mnemonic, password] = words.length === 25
|
||||
? [words.slice(0, 24).join(' '), words[24]]
|
||||
: [words.join(' '), ''];
|
||||
|
||||
assert(mnemonicValidate(mnemonic), 'Invalid mnemonic passed to ledger derivation');
|
||||
assert(hdValidatePath(path), 'Invalid derivation path');
|
||||
|
||||
return naclKeypairFromSeed(
|
||||
path
|
||||
.split('/')
|
||||
.slice(1)
|
||||
.map((n) => parseInt(n.replace(/'$/, ''), 10))
|
||||
.map((n) => (n < HARDENED) ? (n + HARDENED) : n)
|
||||
.reduce((x, n) => ledgerDerivePrivate(x, n), ledgerMaster(mnemonic, password))
|
||||
.slice(0, 32)
|
||||
);
|
||||
const parts = path.split('/').slice(1);
|
||||
let seed = ledgerMaster(mnemonic, password);
|
||||
|
||||
for (const p of parts) {
|
||||
const n = parseInt(p.replace(/'$/, ''), 10);
|
||||
|
||||
seed = ledgerDerivePrivate(seed, (n < HARDENED) ? (n + HARDENED) : n);
|
||||
}
|
||||
|
||||
return naclKeypairFromSeed(seed.slice(0, 32));
|
||||
}
|
||||
|
||||
@@ -10,9 +10,15 @@ export function hdValidatePath (path: string): boolean {
|
||||
|
||||
const parts = path.split('/').slice(1);
|
||||
|
||||
return parts.every((n) => /^\d+'?$/.test(n)) && (
|
||||
!parts
|
||||
.map((n) => parseInt(n.replace(/'$/, ''), 10))
|
||||
.some((n) => isNaN(n) || (n >= HARDENED) || (n < 0))
|
||||
);
|
||||
for (const p of parts) {
|
||||
const n = /^\d+'?$/.test(p)
|
||||
? parseInt(p.replace(/'$/, ''), 10)
|
||||
: Number.NaN;
|
||||
|
||||
if (isNaN(n) || (n >= HARDENED) || (n < 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ export function keyExtractPath (derivePath: string): ExtractResult {
|
||||
if (parts) {
|
||||
constructed = parts.join('');
|
||||
|
||||
parts.forEach((value: string): void => {
|
||||
path.push(DeriveJunction.from(value.substr(1)));
|
||||
});
|
||||
for (const p of parts) {
|
||||
path.push(DeriveJunction.from(p.substr(1)));
|
||||
}
|
||||
}
|
||||
|
||||
assert(constructed === derivePath, () => `Re-constructed path "${constructed}" does not match input`);
|
||||
|
||||
@@ -18,8 +18,11 @@ const generators = {
|
||||
|
||||
export function keyFromPath (pair: Keypair, path: DeriveJunction[], type: KeypairType): Keypair {
|
||||
const keyHdkd = generators[type];
|
||||
let result = pair;
|
||||
|
||||
return path.reduce((pair, junction): Keypair => {
|
||||
return keyHdkd(pair, junction);
|
||||
}, pair);
|
||||
for (const junction of path) {
|
||||
result = keyHdkd(result, junction);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -20,15 +20,19 @@
|
||||
*/
|
||||
export function arrayFlatten <T> (arrays: T[][]): T[] {
|
||||
// pre-allocate based on the combined size
|
||||
const output = new Array<T>(arrays.reduce((length, array) => length + array.length, 0));
|
||||
let size = 0;
|
||||
|
||||
for (const a of arrays) {
|
||||
size += a.length;
|
||||
}
|
||||
|
||||
const output = new Array<T>(size);
|
||||
let index = -1;
|
||||
|
||||
for (let a = 0; a < arrays.length; a++) {
|
||||
const array = arrays[a];
|
||||
|
||||
for (const a of arrays) {
|
||||
// instead of pushing, we just set the entries
|
||||
for (let e = 0; e < array.length; e++) {
|
||||
output[++index] = array[e];
|
||||
for (let e = 0; e < a.length; e++) {
|
||||
output[++index] = a[e];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,5 +21,11 @@ import { assert } from '../assert';
|
||||
export function arrayRange (size: number, startAt = 0): number[] {
|
||||
assert(size > 0, 'Expected non-zero, positive number as a range size');
|
||||
|
||||
return new Array(size).fill(0).map((_, i) => i + startAt);
|
||||
const result = new Array<number>(size).fill(0);
|
||||
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
result[i] = i + startAt;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -9,4 +9,10 @@ describe('bnMax', (): void => {
|
||||
bnMax(new BN(1), new BN(2), new BN(3))
|
||||
).toEqual(new BN(3));
|
||||
});
|
||||
|
||||
it('finds BN maximum', (): void => {
|
||||
expect(
|
||||
bnMax(new BN(2), new BN(3), new BN(1))
|
||||
).toEqual(new BN(3));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import { BN, bnMin } from '.';
|
||||
describe('bnMin', (): void => {
|
||||
it('finds BN minimum', (): void => {
|
||||
expect(
|
||||
bnMin(new BN(1), new BN(2), new BN(3))
|
||||
bnMin(new BN(2), new BN(1), new BN(3))
|
||||
).toEqual(new BN(1));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,5 +7,11 @@ import { BN } from './bn';
|
||||
export function checkMaxMin (type: 'max' | 'min', items: BN[]): BN {
|
||||
assert(items.length >= 1, 'Must provide one or more BN arguments');
|
||||
|
||||
return items.reduce<BN>((a, v) => BN[type](a, v), items[0]);
|
||||
let result = items[0];
|
||||
|
||||
for (const v of items) {
|
||||
result = BN[type](result, v);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -24,11 +24,13 @@ const logTo = {
|
||||
|
||||
function formatOther (value: unknown): unknown {
|
||||
if (value && isObject(value) && value.constructor === Object) {
|
||||
return Object.keys(value).reduce((result: Record<string, unknown>, key): Record<string, unknown> => {
|
||||
result[key] = loggerFormat(value[key]);
|
||||
const result: Record<string, unknown> = {};
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
for (const k of Object.keys(value)) {
|
||||
result[k] = loggerFormat(value[k]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
@@ -44,7 +44,13 @@ function getEntry (name: string): VersionPath[] {
|
||||
}
|
||||
|
||||
function getVersionLength (all: { version: string }[]): number {
|
||||
return all.reduce((max, { version }) => Math.max(max, version.length), 0);
|
||||
let length = 0;
|
||||
|
||||
for (const { version } of all) {
|
||||
length = Math.max(length, version.length);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
@@ -5,10 +5,12 @@ import crypto from 'crypto';
|
||||
|
||||
export { packageInfo } from './packageInfo';
|
||||
|
||||
export function getRandomValues <T extends Uint8Array> (arr: T): T {
|
||||
return crypto.randomBytes(arr.length).reduce((arr, value, index) => {
|
||||
arr[index] = value;
|
||||
export function getRandomValues <T extends Uint8Array> (output: T): T {
|
||||
const bytes = crypto.randomBytes(output.length);
|
||||
|
||||
return arr;
|
||||
}, arr);
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
output[i] = bytes[i];
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -19,18 +19,18 @@ interface RNExt {
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomValuesNative <T extends Uint8Array> (arr: T): T {
|
||||
return Buffer
|
||||
.from((NativeModules as RNExt).RNGetRandomValues.getRandomBase64(arr.length), 'base64')
|
||||
.reduce((arr, byte, index): T => {
|
||||
arr[index] = byte;
|
||||
function getRandomValuesNative <T extends Uint8Array> (output: T): T {
|
||||
const bytes = Buffer.from((NativeModules as RNExt).RNGetRandomValues.getRandomBase64(output.length), 'base64');
|
||||
|
||||
return arr;
|
||||
}, arr);
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
output[i] = bytes[i];
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function getRandomValuesGlobal <T extends Uint8Array> (arr: T): T {
|
||||
return crypto.getRandomValues(arr);
|
||||
function getRandomValuesGlobal <T extends Uint8Array> (output: T): T {
|
||||
return crypto.getRandomValues(output);
|
||||
}
|
||||
|
||||
export const getRandomValues = (
|
||||
|
||||
@@ -9,8 +9,12 @@ export class TextDecoder {
|
||||
}
|
||||
|
||||
decode (value: Uint8Array): string {
|
||||
return value.reduce((str, code): string => {
|
||||
return str + String.fromCharCode(code);
|
||||
}, '');
|
||||
let result = '';
|
||||
|
||||
for (const c of value) {
|
||||
result += String.fromCharCode(c);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user