Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust type asserts #4952

Merged
merged 1 commit into from
Jun 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ Contributed:
Changes:

- Deupe all internal type property getters
- Adjust `@polkadot/types-codec` asserts
- Rename `Base` type to `AbstractBase` (reflecting usage)
- Alias `blockHash` on `rpc.engine.createBlock` return
- Instantiate `Compact/UInt/Int` with `number` when passed
- Adjust name extraction in `PortableRegistry` (maintainability)
- Adjust string type path extraction (maintainability)
Expand Down
21 changes: 14 additions & 7 deletions packages/types-codec/src/abstract/Int.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { HexString } from '@polkadot/util/types';
import type { AnyNumber, Inspect, INumber, IU8a, Registry, UIntBitLength } from '../types';

import { assert, BN, BN_BILLION, BN_HUNDRED, BN_MILLION, BN_QUINTILL, BN_ZERO, bnToBn, bnToHex, bnToU8a, formatBalance, formatNumber, hexToBn, isBn, isHex, isNumber, isString, isU8a, u8aToBn, u8aToNumber } from '@polkadot/util';
import { BN, BN_BILLION, BN_HUNDRED, BN_MILLION, BN_QUINTILL, bnToBn, bnToHex, bnToU8a, formatBalance, formatNumber, hexToBn, isBn, isHex, isNumber, isString, isU8a, u8aToBn, u8aToNumber } from '@polkadot/util';

export const DEFAULT_UINT_BITS = 64;

Expand All @@ -27,15 +27,19 @@ function toPercentage (value: BN, divisor: BN): string {
/** @internal */
function decodeAbstractInt (value: Exclude<AnyNumber, Uint8Array>, isNegative: boolean): string | number {
if (isNumber(value)) {
assert(value <= Number.MAX_SAFE_INTEGER && value >= Number.MIN_SAFE_INTEGER && Number.isInteger(value), 'Number needs to be an integer <= Number.MAX_SAFE_INTEGER, i.e. 2 ^ 53 - 1');
if (!Number.isInteger(value) || value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {
throw new Error('Number needs to be an integer <= Number.MAX_SAFE_INTEGER, i.e. 2 ^ 53 - 1');
}

return value;
} else if (isString(value)) {
if (isHex(value, -1, true)) {
return hexToBn(value, { isLe: false, isNegative }).toString();
}

assert(!(value.includes('.') || value.includes(',') || value.includes('e')), 'String should not contain decimal points or scientific notation');
if (value.includes('.') || value.includes(',') || value.includes('e')) {
throw new Error('String should not contain decimal points or scientific notation');
}

return value;
} else if (isBn(value)) {
Expand Down Expand Up @@ -79,11 +83,14 @@ export abstract class AbstractInt extends BN implements INumber {
this.encodedLength = this.#bitLength / 8;
this.isUnsigned = !isSigned;

const isPositive = this.gte(BN_ZERO);
const maxBits = bitLength - (isSigned && isPositive ? 1 : 0);
const isNegative = this.isNeg();
const maxBits = bitLength - (isSigned && !isNegative ? 1 : 0);

assert(isSigned || isPositive, () => `${this.toRawType()}: Negative number passed to unsigned type`);
assert(super.bitLength() <= maxBits, () => `${this.toRawType()}: Input too large. Found input with ${super.bitLength()} bits, expected ${maxBits}`);
if (isNegative && !isSigned) {
throw new Error(`${this.toRawType()}: Negative number passed to unsigned type`);
} else if (super.bitLength() > maxBits) {
throw new Error(`${this.toRawType()}: Input too large. Found input with ${super.bitLength()} bits, expected ${maxBits}`);
}
}

/**
Expand Down
6 changes: 6 additions & 0 deletions packages/types-codec/src/base/Compact.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { TypeRegistry } from '@polkadot/types';
import { CodecDate, Compact, U32 } from '@polkadot/types-codec';
import { BN } from '@polkadot/util';

import { performance } from '../test/performance';

const CompactU32 = Compact.with(U32);

describe('Compact', (): void => {
const registry = new TypeRegistry();

Expand Down Expand Up @@ -88,4 +92,6 @@ describe('Compact', (): void => {
});
});
});

performance('Compact', 75_000, [[new Uint8Array([63 << 2])]], (v: Uint8Array) => new CompactU32(registry, v));
});
18 changes: 13 additions & 5 deletions packages/types-codec/src/base/Enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { HexString } from '@polkadot/util/types';
import type { AnyJson, Codec, CodecClass, IEnum, Inspect, IU8a, Registry } from '../types';

import { assert, isHex, isNumber, isObject, isString, isU8a, isUndefined, objectProperties, stringCamelCase, stringify, stringPascalCase, u8aConcatStrict, u8aToHex, u8aToU8a } from '@polkadot/util';
import { isHex, isNumber, isObject, isString, isU8a, isUndefined, objectProperties, stringCamelCase, stringify, stringPascalCase, u8aConcatStrict, u8aToHex, u8aToU8a } from '@polkadot/util';

import { mapToTypeMap, typesToMap } from '../utils';
import { Null } from './Null';
Expand Down Expand Up @@ -45,7 +45,9 @@ function isRustEnum (def: Record<string, string | CodecClass> | Record<string, n
const defValues = Object.values(def);

if (defValues.some((v) => isNumber(v))) {
assert(defValues.every((v) => isNumber(v) && v >= 0 && v <= 255), 'Invalid number-indexed enum definition');
if (!defValues.every((v) => isNumber(v) && v >= 0 && v <= 255)) {
throw new Error('Invalid number-indexed enum definition');
}

return false;
}
Expand Down Expand Up @@ -97,7 +99,9 @@ function extractDef (registry: Registry, _def: Record<string, string | CodecClas
function createFromValue (registry: Registry, def: TypesDef, index = 0, value?: unknown): Decoded {
const entry = Object.values(def).find((e) => e.index === index);

assert(!isUndefined(entry), () => `Unable to create Enum via index ${index}, in ${Object.keys(def).join(', ')}`);
if (isUndefined(entry)) {
throw new Error(`Unable to create Enum via index ${index}, in ${Object.keys(def).join(', ')}`);
}

return {
index,
Expand All @@ -114,7 +118,9 @@ function decodeFromJSON (registry: Registry, def: TypesDef, key: string, value?:
const keyLower = key.toLowerCase();
const index = keys.indexOf(keyLower);

assert(index !== -1, () => `Cannot map Enum JSON, unable to find '${key}' in ${keys.join(', ')}`);
if (index === -1) {
throw new Error(`Cannot map Enum JSON, unable to find '${key}' in ${keys.join(', ')}`);
}

try {
return createFromValue(registry, def, Object.values(def)[index].index, value);
Expand Down Expand Up @@ -223,7 +229,9 @@ export class Enum implements IEnum {

objectProperties(this, isKeys, (_, i) => this.type === keys[i]);
objectProperties(this, asKeys, (k, i): Codec => {
assert(this[isKeys[i] as keyof this], () => `Cannot convert '${this.type}' via ${k}`);
if (!this[isKeys[i] as keyof this]) {
throw new Error(`Cannot convert '${this.type}' via ${k}`);
}

return this.value;
});
Expand Down
6 changes: 4 additions & 2 deletions packages/types-codec/src/base/Option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { HexString } from '@polkadot/util/types';
import type { AnyJson, Codec, CodecClass, Inspect, IOption, IU8a, Registry } from '../types';

import { assert, isCodec, isNull, isU8a, isUndefined, u8aToHex } from '@polkadot/util';
import { isCodec, isNull, isU8a, isUndefined, u8aToHex } from '@polkadot/util';

import { typeToConstructor } from '../utils';
import { Null } from './Null';
Expand Down Expand Up @@ -247,7 +247,9 @@ export class Option<T extends Codec> implements IOption<T> {
* @description Returns the value that the Option represents (if available), throws if null
*/
public unwrap (): T {
assert(this.isSome, 'Option: unwrapping a None value');
if (this.isNone) {
throw new Error('Option: unwrapping a None value');
}

return this.#raw;
}
Expand Down
10 changes: 6 additions & 4 deletions packages/types-codec/src/base/Result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

import type { Codec, CodecClass, IResult, Registry } from '../types';

import { assert } from '@polkadot/util';

import { Enum } from './Enum';

/**
Expand All @@ -31,7 +29,9 @@ export class Result<O extends Codec, E extends Codec> extends Enum implements IR
* @description Returns the wrapper Err value (if isErr)
*/
public get asErr (): E {
assert(this.isErr, 'Cannot extract Err value from Ok result, check isErr first');
if (!this.isErr) {
throw new Error('Cannot extract Err value from Ok result, check isErr first');
}

return this.value as E;
}
Expand All @@ -47,7 +47,9 @@ export class Result<O extends Codec, E extends Codec> extends Enum implements IR
* @description Returns the wrapper Ok value (if isOk)
*/
public get asOk (): O {
assert(this.isOk, 'Cannot extract Ok value from Err result, check isOk first');
if (!this.isOk) {
throw new Error('Cannot extract Ok value from Err result, check isOk first');
}

return this.value as O;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/types-codec/src/base/UInt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { TypeRegistry } from '@polkadot/types';
import { UInt } from '@polkadot/types-codec';
import { BN, BN_TWO, isBn } from '@polkadot/util';

import { performance } from '../test/performance';

describe('UInt', (): void => {
const registry = new TypeRegistry();

Expand Down Expand Up @@ -180,4 +182,6 @@ describe('UInt', (): void => {
expect(registry.createType('Balance', '123456789012345').toHuman()).toEqual('123.4567 Unit');
});
});

performance('UInt', 75_000, [[new Uint8Array([31, 32, 33, 34])]], (v: Uint8Array) => new UInt(registry, v));
});
7 changes: 6 additions & 1 deletion packages/types-codec/src/base/Vec.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import type { PropIndex } from '@polkadot/types/interfaces/democracy';
import type { Codec, CodecTo, ITuple } from '@polkadot/types-codec/types';

import { createTypeUnsafe, GenericAccountId as AccountId, Metadata, TypeRegistry } from '@polkadot/types';
import { Text, Vec } from '@polkadot/types-codec';
import { Text, u32, Vec } from '@polkadot/types-codec';
import rpcMetadata from '@polkadot/types-support/metadata/static-substrate';
import { decodeAddress, randomAsU8a } from '@polkadot/util-crypto';

import { performance } from '../test/performance';

const registry = new TypeRegistry();
const metadata = new Metadata(registry, rpcMetadata);
const VecU32 = Vec.with(u32);

registry.setMetadata(metadata);

Expand Down Expand Up @@ -190,4 +193,6 @@ describe('Vec', (): void => {
});
});
});

performance('Vec<U32>', 40_000, [[new Uint8Array([3 << 2, 11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34])]], (v: Uint8Array) => new VecU32(registry, v));
});
6 changes: 4 additions & 2 deletions packages/types-codec/src/base/Vec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { HexString } from '@polkadot/util/types';
import type { Codec, CodecClass, Registry } from '../types';

import { assert, compactFromU8aLim, isU8a, logger, u8aToU8a } from '@polkadot/util';
import { compactFromU8aLim, isU8a, logger, u8aToU8a } from '@polkadot/util';

import { AbstractArray } from '../abstract/Array';
import { decodeU8aVec, typeToConstructor } from '../utils';
Expand All @@ -30,7 +30,9 @@ function decodeVecLength (value: Uint8Array | HexString | unknown[]): [Uint8Arra
const u8a = u8aToU8a(value);
const [startAt, length] = compactFromU8aLim(u8a);

assert(length <= MAX_LENGTH, () => `Vec length ${length.toString()} exceeds ${MAX_LENGTH}`);
if (length > MAX_LENGTH) {
throw new Error(`Vec length ${length.toString()} exceeds ${MAX_LENGTH}`);
}

return [u8a, length, startAt];
}
Expand Down
6 changes: 4 additions & 2 deletions packages/types-codec/src/extended/BitVec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import type { AnyU8a, Inspect, Registry } from '../types';

import { assert, compactFromU8aLim, compactToU8a, isString, u8aConcatStrict, u8aToU8a } from '@polkadot/util';
import { compactFromU8aLim, compactToU8a, isString, u8aConcatStrict, u8aToU8a } from '@polkadot/util';

import { Raw } from '../native/Raw';

Expand All @@ -17,7 +17,9 @@ function decodeBitVecU8a (value?: Uint8Array): [number, Uint8Array] {
const [offset, length] = compactFromU8aLim(value);
const total = offset + Math.ceil(length / 8);

assert(total <= value.length, () => `BitVec: required length less than remainder, expected at least ${total}, found ${value.length}`);
if (total > value.length) {
throw new Error(`BitVec: required length less than remainder, expected at least ${total}, found ${value.length}`);
}

return [length, value.subarray(offset, total)];
}
Expand Down
9 changes: 6 additions & 3 deletions packages/types-codec/src/extended/Bytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import type { AnyU8a, Inspect, Registry } from '../types';

import { assert, compactAddLength, compactFromU8aLim, compactToU8a, isString, isU8a, u8aToU8a } from '@polkadot/util';
import { compactAddLength, compactFromU8aLim, compactToU8a, isString, isU8a, u8aToU8a } from '@polkadot/util';

import { Raw } from '../native/Raw';

Expand All @@ -20,8 +20,11 @@ function decodeBytesU8a (value: Uint8Array): [Uint8Array, number] {
const [offset, length] = compactFromU8aLim(value);
const total = offset + length;

assert(length <= MAX_LENGTH, () => `Bytes length ${length.toString()} exceeds ${MAX_LENGTH}`);
assert(total <= value.length, () => `Bytes: required length less than remainder, expected at least ${total}, found ${value.length}`);
if (length > MAX_LENGTH) {
throw new Error(`Bytes length ${length.toString()} exceeds ${MAX_LENGTH}`);
} else if (total > value.length) {
throw new Error(`Bytes: required length less than remainder, expected at least ${total}, found ${value.length}`);
}

return [value.subarray(offset, total), total];
}
Expand Down
6 changes: 4 additions & 2 deletions packages/types-codec/src/extended/U8aFixed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import type { AnyU8a, CodecClass, Registry, U8aBitLength } from '../types';

import { assert, isU8a, u8aToU8a } from '@polkadot/util';
import { isU8a, u8aToU8a } from '@polkadot/util';

import { Raw } from '../native/Raw';

Expand All @@ -16,7 +16,9 @@ function decodeU8aFixed (value: AnyU8a, bitLength: U8aBitLength): [AnyU8a, numbe
return [new Uint8Array(byteLength), 0];
}

assert(isU8a(value) ? u8a.length >= byteLength : u8a.length === byteLength, () => `Expected input with ${byteLength} bytes (${bitLength} bits), found ${u8a.length} bytes`);
if (isU8a(value) ? u8a.length < byteLength : u8a.length !== byteLength) {
throw new Error(`Expected input with ${byteLength} bytes (${bitLength} bits), found ${u8a.length} bytes`);
}

return [u8a.subarray(0, byteLength), byteLength];
}
Expand Down
8 changes: 6 additions & 2 deletions packages/types-codec/src/extended/WrapperKeepOpaque.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import type { AnyJson, AnyU8a, Codec, CodecClass, Inspect, Registry } from '../types';

import { assertReturn, compactAddLength, compactStripLength, compactToU8a, isHex, isU8a } from '@polkadot/util';
import { compactAddLength, compactStripLength, compactToU8a, isHex, isU8a } from '@polkadot/util';

import { Raw } from '../native/Raw';
import { typeToConstructor } from '../utils';
Expand Down Expand Up @@ -110,6 +110,10 @@ export class WrapperKeepOpaque<T extends Codec> extends Bytes {
* @description Returns the decoded that the WrapperKeepOpaque represents (if available), throws if non-decodable
*/
public unwrap (): T {
return assertReturn(this.#decoded, () => `${this.#opaqueName}: unwrapping an undecodable value`);
if (!this.#decoded) {
throw new Error(`${this.#opaqueName}: unwrapping an undecodable value`);
}

return this.#decoded;
}
}
6 changes: 4 additions & 2 deletions packages/types-codec/src/native/Raw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { HexString } from '@polkadot/util/types';
import type { AnyJson, AnyU8a, Inspect, IU8a, Registry } from '../types';

import { assert, isAscii, isUndefined, isUtf8, u8aToHex, u8aToString, u8aToU8a } from '@polkadot/util';
import { isAscii, isUndefined, isUtf8, u8aToHex, u8aToString, u8aToU8a } from '@polkadot/util';

/**
* @name Raw
Expand Down Expand Up @@ -177,7 +177,9 @@ export class Raw extends Uint8Array implements IU8a {
* @description Returns the wrapped data as a UTF-8 string
*/
public toUtf8 (): string {
assert(this.isUtf8, 'The character sequence is not a valid Utf8 string');
if (!this.isUtf8) {
throw new Error('The character sequence is not a valid Utf8 string');
}

return u8aToString(this);
}
Expand Down
18 changes: 13 additions & 5 deletions packages/types-codec/src/native/Set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { HexString } from '@polkadot/util/types';
import type { CodecClass, Inspect, ISet, IU8a, Registry } from '../types';

import { assert, BN, bnToBn, bnToU8a, isBn, isNumber, isString, isU8a, isUndefined, objectProperties, stringify, stringPascalCase, u8aToBn, u8aToHex, u8aToU8a } from '@polkadot/util';
import { BN, bnToBn, bnToU8a, isBn, isNumber, isString, isU8a, isUndefined, objectProperties, stringify, stringPascalCase, u8aToBn, u8aToHex, u8aToU8a } from '@polkadot/util';

import { compareArray } from '../utils';

Expand All @@ -27,7 +27,9 @@ function decodeSetArray (setValues: SetValues, values: string[]): string[] {
for (let i = 0; i < values.length; i++) {
const key = values[i];

assert(!isUndefined(setValues[key]), () => `Set: Invalid key '${key}' passed to Set, allowed ${Object.keys(setValues).join(', ')}`);
if (isUndefined(setValues[key])) {
throw new Error(`Set: Invalid key '${key}' passed to Set, allowed ${Object.keys(setValues).join(', ')}`);
}

result[i] = key;
}
Expand All @@ -51,14 +53,18 @@ function decodeSetNumber (setValues: SetValues, _value: BN | number): string[] {

const computed = encodeSet(setValues, result);

assert(bn.eq(computed), () => `Set: Mismatch decoding '${bn.toString()}', computed as '${computed.toString()}' with ${result.join(', ')}`);
if (!bn.eq(computed)) {
throw new Error(`Set: Mismatch decoding '${bn.toString()}', computed as '${computed.toString()}' with ${result.join(', ')}`);
}

return result;
}

/** @internal */
function decodeSet (setValues: SetValues, value: string[] | Set<string> | Uint8Array | BN | number | string = 0, bitLength: number): string[] {
assert(bitLength % 8 === 0, () => `Expected valid bitLength, power of 8, found ${bitLength}`);
if (bitLength % 8 !== 0) {
throw new Error(`Expected valid bitLength, power of 8, found ${bitLength}`);
}

const byteLength = bitLength / 8;

Expand Down Expand Up @@ -161,7 +167,9 @@ export class CodecSet extends Set<string> implements ISet<string> {
// ^^^ add = () property done to assign this instance's this, otherwise Set.add creates "some" chaos
// we have the isUndefined(this._setValues) in here as well, add is used internally
// in the Set constructor (so it is undefined at this point, and should allow)
assert(isUndefined(this.#allowed) || !isUndefined(this.#allowed[key]), () => `Set: Invalid key '${key}' on add`);
if (this.#allowed && isUndefined(this.#allowed[key])) {
throw new Error(`Set: Invalid key '${key}' on add`);
}

super.add(key);

Expand Down
Loading