Struct decoding error messaging (#3425)

* Struct decoding error messaging

* Error adjust

* Tests

* Bump common, use stringify

* Linting

* Adjust

* Bumps

* Rebump

* Assert cleanups

* Don't modify original value on encoding

* util bump, fixe compact encoding
This commit is contained in:
Jaco
2021-04-22 15:02:54 +02:00
committed by GitHub
parent 88b84dcf75
commit 557283a3d1
57 changed files with 267 additions and 247 deletions
+4 -4
View File
@@ -7,7 +7,7 @@ import type { UIntBitLength } from './types';
import BN from 'bn.js';
import { assert, BN_BILLION, BN_HUNDRED, BN_MILLION, BN_QUINTILL, BN_ZERO, bnToBn, bnToHex, bnToU8a, formatBalance, formatNumber, hexToBn, isHex, isString, isU8a, u8aToBn } from '@polkadot/util';
import { assert, BN_BILLION, BN_HUNDRED, BN_MILLION, BN_QUINTILL, BN_ZERO, bnToBn, bnToHex, bnToU8a, formatBalance, formatNumber, hexToBn, isHex, isString, isU8a, stringify, u8aToBn } from '@polkadot/util';
export const DEFAULT_UINT_BITS = 64;
@@ -37,7 +37,7 @@ function decodeAbstracIntU8a (value: Uint8Array, bitLength: UIntBitLength, isNeg
// NOTE When passing u8a in (typically from decoded data), it is always Little Endian
return u8aToBn(value.subarray(0, bitLength / 8), { isLe: true, isNegative }).toString();
} catch (error) {
throw new Error(`AbstractInt: failed on ${JSON.stringify(value)}:: ${(error as Error).message}`);
throw new Error(`AbstractInt: failed on ${stringify(value)}:: ${(error as Error).message}`);
}
}
@@ -83,8 +83,8 @@ export abstract class AbstractInt extends BN implements Codec {
const isPositive = this.gte(BN_ZERO);
const maxBits = bitLength - (isSigned && isPositive ? 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}`);
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}`);
}
/**
+2 -2
View File
@@ -4,7 +4,7 @@
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyJson, Codec, Constructor, InterfaceTypes, Registry } from '../types';
import { compactFromU8a, compactToU8a, isHex, isU8a, logger, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { compactFromU8a, compactToU8a, isHex, isU8a, logger, stringify, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { compareSet, decodeU8a, typeToConstructor } from './utils';
@@ -176,7 +176,7 @@ export class BTreeSet<V extends Codec = Codec> extends Set<V> implements Codec {
* @description Returns the string representation of the value
*/
public toString (): string {
return JSON.stringify(this.toJSON());
return stringify(this.toJSON());
}
/**
+2 -4
View File
@@ -3,7 +3,7 @@
import type { CodecHash, Hash } from '../interfaces';
import type { AnyJson, AnyNumber, Constructor, ICompact, InterfaceTypes, Registry } from '../types';
import type { CompactEncodable, UIntBitLength } from './types';
import type { CompactEncodable } from './types';
import BN from 'bn.js';
@@ -50,9 +50,7 @@ export class Compact<T extends CompactEncodable> implements ICompact<T> {
return new Type(registry, value);
}
const [, _value] = compactFromU8a(value, new Type(registry, 0).bitLength() as UIntBitLength);
return new Type(registry, _value);
return new Type(registry, compactFromU8a(value)[1]);
}
/**
+6 -6
View File
@@ -4,7 +4,7 @@
import type { CodecHash, Hash } from '../interfaces';
import type { AnyJson, Codec, Constructor, InterfaceTypes, Registry } from '../types';
import { assert, hexToU8a, isHex, isNumber, isObject, isString, isU8a, isUndefined, stringCamelCase, stringUpperFirst, u8aConcat, u8aToHex } from '@polkadot/util';
import { assert, hexToU8a, isHex, isNumber, isObject, isString, isU8a, isUndefined, stringCamelCase, stringify, stringUpperFirst, u8aConcat, u8aToHex } from '@polkadot/util';
import { Null } from '../primitive/Null';
import { Struct } from './Struct';
@@ -88,7 +88,7 @@ function extractDef (registry: Registry, _def: Record<string, keyof InterfaceTyp
function createFromValue (registry: Registry, def: TypesDef, index = 0, value?: any): 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(', ')}`);
assert(!isUndefined(entry), () => `Unable to create Enum via index ${index}, in ${Object.keys(def).join(', ')}`);
return {
index,
@@ -105,7 +105,7 @@ 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(', ')}`);
assert(index !== -1, () => `Cannot map Enum JSON, unable to find '${key}' in ${keys.join(', ')}`);
try {
return createFromValue(registry, def, Object.values(def)[index].index, value);
@@ -213,7 +213,7 @@ export class Enum implements Codec {
Object.defineProperty(this, askey, {
enumerable: true,
get: (): Codec => {
assert(this[iskey as keyof this], `Cannot convert '${this.type}' via ${askey}`);
assert(this[iskey as keyof this], () => `Cannot convert '${this.type}' via ${askey}`);
return this.value;
}
@@ -384,7 +384,7 @@ export class Enum implements Codec {
* @description Returns the base runtime type name for this instance
*/
public toRawType (): string {
return JSON.stringify({ _enum: this._toRawStruct() });
return stringify({ _enum: this._toRawStruct() });
}
/**
@@ -393,7 +393,7 @@ export class Enum implements Codec {
public toString (): string {
return this.isNull
? this.type
: JSON.stringify(this.toJSON());
: stringify(this.toJSON());
}
/**
+2 -2
View File
@@ -4,7 +4,7 @@
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyJson, Codec, Registry } from '../types';
import { isFunction, isUndefined } from '@polkadot/util';
import { isFunction, isUndefined, stringify } from '@polkadot/util';
import { compareMap } from './utils';
@@ -112,7 +112,7 @@ export class Json extends Map<string, any> implements Codec {
* @description Returns the string representation of the value
*/
public toString (): string {
return JSON.stringify(this.toJSON());
return stringify(this.toJSON());
}
/**
+2 -2
View File
@@ -4,7 +4,7 @@
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyJson, Codec, Constructor, InterfaceTypes, Registry } from '../types';
import { compactFromU8a, compactToU8a, isHex, isObject, isU8a, logger, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { compactFromU8a, compactToU8a, isHex, isObject, isU8a, logger, stringify, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { compareMap, decodeU8a, typeToConstructor } from './utils';
@@ -183,7 +183,7 @@ export class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends
* @description Returns the string representation of the value
*/
public toString (): string {
return JSON.stringify(this.toJSON());
return stringify(this.toJSON());
}
/**
+6 -6
View File
@@ -6,7 +6,7 @@ import type { Codec, Constructor, Registry } from '../types';
import BN from 'bn.js';
import { assert, bnToBn, bnToU8a, isBn, isNumber, isString, isU8a, isUndefined, stringCamelCase, stringUpperFirst, u8aToBn, u8aToHex, u8aToU8a } from '@polkadot/util';
import { assert, bnToBn, bnToU8a, isBn, isNumber, isString, isU8a, isUndefined, stringCamelCase, stringify, stringUpperFirst, u8aToBn, u8aToHex, u8aToU8a } from '@polkadot/util';
import { compareArray } from './utils';
@@ -21,7 +21,7 @@ function encodeSet (setValues: SetValues, value: string[]): BN {
/** @internal */
function decodeSetArray (setValues: SetValues, value: string[]): string[] {
return value.reduce((result, key): string[] => {
assert(!isUndefined(setValues[key]), `Set: Invalid key '${key}' passed to Set, allowed ${Object.keys(setValues).join(', ')}`);
assert(!isUndefined(setValues[key]), () => `Set: Invalid key '${key}' passed to Set, allowed ${Object.keys(setValues).join(', ')}`);
result.push(key);
@@ -42,14 +42,14 @@ 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(', ')}`);
assert(bn.eq(computed), () => `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}`);
assert(bitLength % 8 === 0, () => `Expected valid bitLength, power of 8, found ${bitLength}`);
const byteLength = bitLength / 8;
@@ -155,7 +155,7 @@ export class CodecSet extends Set<string> implements Codec {
// ^^^ 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`);
assert(isUndefined(this.#allowed) || !isUndefined(this.#allowed[key]), () => `Set: Invalid key '${key}' on add`);
super.add(key);
@@ -210,7 +210,7 @@ export class CodecSet extends Set<string> implements Codec {
* @description Returns the base runtime type name for this instance
*/
public toRawType (): string {
return JSON.stringify({ _set: this.#allowed });
return stringify({ _set: this.#allowed });
}
/**
+8
View File
@@ -119,6 +119,14 @@ describe('Struct', (): void => {
).toThrowError(/Cannot decode value/);
});
it('throws a sensical error on incorrect array values passed to structs', (): void => {
expect(
() => new Struct(registry, {
_: 'Vec<u32>'
}, [123, 456])
).toThrow(/array to object with known keys/);
});
it('provides a clean toString()', (): void => {
expect(
new (
+8 -5
View File
@@ -4,7 +4,7 @@
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyJson, BareOpts, Codec, Constructor, ConstructorDef, InterfaceTypes, Registry } from '../types';
import { hexToU8a, isBoolean, isFunction, isHex, isObject, isU8a, isUndefined, stringCamelCase, u8aConcat, u8aToHex } from '@polkadot/util';
import { assert, hexToU8a, isBoolean, isFunction, isHex, isObject, isU8a, isUndefined, stringCamelCase, stringify, u8aConcat, u8aToHex } from '@polkadot/util';
import { compareMap, decodeU8a, mapToTypeMap } from './utils';
@@ -13,8 +13,11 @@ type TypesDef<T = Codec> = Record<string, keyof InterfaceTypes | Constructor<T>>
/** @internal */
function decodeStructFromObject <T> (registry: Registry, Types: ConstructorDef, value: any, jsonMap: Map<any, string>): T {
let jsonObj: Record<string, any> | undefined;
const inputKeys = Object.keys(Types);
return Object.keys(Types).reduce((raw, key, index): T => {
assert(!Array.isArray(value) || value.length === inputKeys.length, () => `Struct: Unable to map ${stringify(value)} array to object with known keys ${inputKeys.join(', ')}`);
return inputKeys.reduce((raw, key, index): T => {
// The key in the JSON can be snake_case (or other cases), but in our
// Types, result or any other maps, it's camelCase
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
@@ -60,7 +63,7 @@ function decodeStructFromObject <T> (registry: Registry, Types: ConstructorDef,
? assign
: new Types[key](registry, assign);
} else {
throw new Error(`Cannot decode value ${JSON.stringify(value)}`);
throw new Error(`Cannot decode value ${stringify(value)} (typeof ${typeof value}), expected an input object with known keys`);
}
} catch (error) {
let type = Types[key].name;
@@ -297,7 +300,7 @@ export class Struct<
* @description Returns the base runtime type name for this instance
*/
public toRawType (): string {
return JSON.stringify(
return stringify(
Struct.typesToMap(this.registry, this.#Types)
);
}
@@ -306,7 +309,7 @@ export class Struct<
* @description Returns the string representation of the value
*/
public toString (): string {
return JSON.stringify(this.toJSON());
return stringify(this.toJSON());
}
/**
+2 -2
View File
@@ -3,7 +3,7 @@
import type { AnyNumber, AnyString, AnyU8a, Codec, Constructor, InterfaceTypes, Registry } from '../types';
import { isHex, isU8a, u8aConcat, u8aToU8a } from '@polkadot/util';
import { isHex, isU8a, stringify, u8aConcat, u8aToU8a } from '@polkadot/util';
import { AbstractArray } from './AbstractArray';
import { decodeU8a, mapToTypeMap, typeToConstructor } from './utils';
@@ -110,7 +110,7 @@ export class Tuple extends AbstractArray<Codec> {
*/
public toString (): string {
// Overwrite the default toString representation of Array.
return JSON.stringify(this.toJSON());
return stringify(this.toJSON());
}
/**
+1 -1
View File
@@ -50,7 +50,7 @@ export class Vec<T extends Codec> extends AbstractArray<T> {
const u8a = u8aToU8a(value);
const [offset, length] = compactFromU8a(u8a);
assert(length.lten(MAX_LENGTH), `Vec length ${length.toString()} exceeds ${MAX_LENGTH}`);
assert(length.lten(MAX_LENGTH), () => `Vec length ${length.toString()} exceeds ${MAX_LENGTH}`);
return decodeU8a(registry, u8a.subarray(offset), new Array(length.toNumber()).fill(Type)) as T[];
}
+1 -1
View File
@@ -39,7 +39,7 @@ export class VecFixed<T extends Codec> extends AbstractArray<T> {
values.push(new Type(registry));
}
assert(values.length === allocLength, `Expected a length of exactly ${allocLength} entries`);
assert(values.length === allocLength, () => `Expected a length of exactly ${allocLength} entries`);
return values;
}
+5 -5
View File
@@ -5,7 +5,7 @@ import type { U8aBitLength, UIntBitLength } from '../codec/types';
import type { Codec, Constructor, InterfaceTypes, Registry } from '../types';
import type { FromReg, TypeDef } from './types';
import { assert, isNumber, isUndefined } from '@polkadot/util';
import { assert, isNumber, isUndefined, stringify } from '@polkadot/util';
import { BTreeMap, BTreeSet, CodecSet, Compact, Enum, HashMap, Int, Option, Result, Struct, Tuple, U8aFixed, UInt, Vec, VecFixed } from '../codec';
import { DoNotConstruct } from '../primitive';
@@ -33,13 +33,13 @@ export function ClassOf<K extends keyof InterfaceTypes> (registry: Registry, nam
}
function getSubDefArray (value: TypeDef): TypeDef[] {
assert(value.sub && Array.isArray(value.sub), `Expected subtype as TypeDef[] in ${JSON.stringify(value)}`);
assert(value.sub && Array.isArray(value.sub), () => `Expected subtype as TypeDef[] in ${stringify(value)}`);
return value.sub;
}
function getSubDef (value: TypeDef): TypeDef {
assert(value.sub && !Array.isArray(value.sub), `Expected subtype as TypeDef in ${JSON.stringify(value)}`);
assert(value.sub && !Array.isArray(value.sub), () => `Expected subtype as TypeDef in ${stringify(value)}`);
return value.sub;
}
@@ -67,7 +67,7 @@ function getTypeClassArray (value: TypeDef): (keyof InterfaceTypes)[] {
}
function createInt ({ displayName, length }: TypeDef, Clazz: typeof Int | typeof UInt): Constructor {
assert(isNumber(length), `Expected bitLength information for ${displayName || Clazz.constructor.name}<bitLength>`);
assert(isNumber(length), () => `Expected bitLength information for ${displayName || Clazz.constructor.name}<bitLength>`);
return Clazz.with(length as UIntBitLength, displayName);
}
@@ -185,7 +185,7 @@ export function getTypeClass<T extends Codec = Codec> (registry: Registry, value
const getFn = infoMapping[value.info];
assert(getFn, `Unable to construct class from ${JSON.stringify(value)}`);
assert(getFn, () => `Unable to construct class from ${stringify(value)}`);
return getFn(registry, value) as Constructor<T>;
}
+7 -7
View File
@@ -3,7 +3,7 @@
import type { TypeDef } from './types';
import { assert, isNumber, isUndefined } from '@polkadot/util';
import { assert, isNumber, isUndefined, stringify } from '@polkadot/util';
import { TypeDefInfo } from './types';
@@ -34,7 +34,7 @@ function encodeWithParams (typeDef: TypeDef, outer: string): string {
return paramsNotation(outer, sub, (param) => encodeTypeDef(param));
}
throw new Error(`Unable to encode ${JSON.stringify(typeDef)} with params`);
throw new Error(`Unable to encode ${stringify(typeDef)} with params`);
}
function encodeDoNotConstruct ({ displayName }: TypeDef): string {
@@ -44,14 +44,14 @@ function encodeDoNotConstruct ({ displayName }: TypeDef): string {
function encodeSubTypes (sub: TypeDef[], asEnum?: boolean): string {
const names = sub.map(({ name }) => name);
assert(names.every((n) => !!n), `Subtypes does not have consistent names, ${names.join(', ')}`);
assert(names.every((n) => !!n), () => `Subtypes does not have consistent names, ${names.join(', ')}`);
const inner = sub.reduce((result: Record<string, string>, type): Record<string, string> => ({
...result,
[type.name as string]: encodeTypeDef(type)
}), {});
return JSON.stringify(
return stringify(
asEnum
? { _enum: inner }
: inner
@@ -66,7 +66,7 @@ function encodeEnum (typeDef: TypeDef): string {
// c-like enums have all Null entries
// TODO We need to take the disciminant into account and auto-add empty entries
return sub.every(({ type }) => type === 'Null')
? JSON.stringify({ _enum: sub.map(({ name }, index) => `${name || `Empty${index}`}`) })
? stringify({ _enum: sub.map(({ name }, index) => `${name || `Empty${index}`}`) })
: encodeSubTypes(sub, true);
}
@@ -121,13 +121,13 @@ const encoders: Record<TypeDefInfo, (typeDef: TypeDef) => string> = {
function encodeType (typeDef: TypeDef): string {
const encoder = encoders[typeDef.info];
assert(encoder, `Cannot encode type: ${JSON.stringify(typeDef)}`);
assert(encoder, () => `Cannot encode type: ${stringify(typeDef)}`);
return encoder(typeDef);
}
export function encodeTypeDef (typeDef: TypeDef): string {
assert(!isUndefined(typeDef.info), `Invalid type definition with no instance info, ${JSON.stringify(typeDef)}`);
assert(!isUndefined(typeDef.info), () => `Invalid type definition with no instance info, ${stringify(typeDef)}`);
// In the case of contracts we do have the unfortunate situation where the displayName would
// refer to "Option" when it is an option. For these, string it out, only using when actually
+2 -2
View File
@@ -110,7 +110,7 @@ function _decodeFixedVec (value: TypeDef, type: string, _: string, count: number
const length = parseInt(strLength.trim(), 10);
// as a first round, only u8 via u8aFixed, we can add more support
assert(length <= 256, `${type}: Only support for [Type; <length>], where length <= 256`);
assert(length <= 256, () => `${type}: Only support for [Type; <length>], where length <= 256`);
value.displayName = displayName;
value.length = length;
@@ -137,7 +137,7 @@ function _decodeAnyInt (value: TypeDef, type: string, _: string, clazz: 'Int' |
const length = parseInt(strLength.trim(), 10);
// as a first round, only u8 via u8aFixed, we can add more support
assert(length <= 8192 && (length % 8) === 0, `${type}: Only support for ${clazz}<bitLength>, where length <= 8192 and a power of 8, found ${length}`);
assert(length <= 8192 && (length % 8) === 0, () => `${type}: Only support for ${clazz}<bitLength>, where length <= 8192 and a power of 8, found ${length}`);
value.displayName = displayName;
value.length = length;
+5 -5
View File
@@ -10,7 +10,7 @@ import type { CallFunction, Codec, CodecHasher, Constructor, InterfaceTypes, Reg
// we are attempting to avoid circular refs, hence the Metadata path import
import { decorateConstants, decorateExtrinsics } from '@polkadot/metadata/decorate';
import { Metadata } from '@polkadot/metadata/Metadata';
import { assert, assertReturn, BN_ZERO, formatBalance, isFunction, isString, isU8a, logger, stringCamelCase, u8aToHex } from '@polkadot/util';
import { assert, assertReturn, BN_ZERO, formatBalance, isFunction, isString, isU8a, logger, stringCamelCase, stringify, u8aToHex } from '@polkadot/util';
import { blake2AsU8a } from '@polkadot/util-crypto';
import { Json } from '../codec/Json';
@@ -340,8 +340,8 @@ export class TypeRegistry implements Registry {
if (isFunction(arg1)) {
this.#classes.set(arg1.name, arg1);
} else if (isString(arg1)) {
assert(isFunction(arg2), `Expected class definition passed to '${arg1}' registration`);
assert(arg1 !== arg2.toString(), `Unable to register circular ${arg1} === ${arg1}`);
assert(isFunction(arg2), () => `Expected class definition passed to '${arg1}' registration`);
assert(arg1 !== arg2.toString(), () => `Unable to register circular ${arg1} === ${arg1}`);
this.#classes.set(arg1, arg2);
} else {
@@ -357,9 +357,9 @@ export class TypeRegistry implements Registry {
} else {
const def = isString(type)
? type
: JSON.stringify(type);
: stringify(type);
assert(name !== def, `Unable to register circular ${name} === ${def}`);
assert(name !== def, () => `Unable to register circular ${name} === ${def}`);
// we already have this type, remove the classes registered for it
if (this.#classes.has(name)) {
+1 -1
View File
@@ -42,7 +42,7 @@ export function typeSplit (type: string): string[] {
}
}
assert(isNotNested(cDepth, fDepth, sDepth, tDepth), `Invalid definition (missing terminators) found in ${type}`);
assert(isNotNested(cDepth, fDepth, sDepth, tDepth), () => `Invalid definition (missing terminators) found in ${type}`);
// the final leg of the journey
result.push(type.substr(start, type.length - start).trim());
+1 -1
View File
@@ -206,7 +206,7 @@ export class GenericExtrinsic<A extends AnyTuple = AnyTuple> extends ExtrinsicBa
const [offset, length] = compactFromU8a(value);
const total = offset + length.toNumber();
assert(total <= value.length, `Extrinsic: length less than remainder, expected at least ${total}, found ${value.length}`);
assert(total <= value.length, () => `Extrinsic: length less than remainder, expected at least ${total}, found ${value.length}`);
const data = value.subarray(offset, total);
+2 -2
View File
@@ -246,7 +246,7 @@ export class GenericExtrinsicEra extends Enum implements IExtrinsicEra {
* @description Returns the item as a [[ImmortalEra]]
*/
public get asImmortalEra (): ImmortalEra {
assert(this.isImmortalEra, `Cannot convert '${this.type}' via asImmortalEra`);
assert(this.isImmortalEra, () => `Cannot convert '${this.type}' via asImmortalEra`);
return this.value as ImmortalEra;
}
@@ -255,7 +255,7 @@ export class GenericExtrinsicEra extends Enum implements IExtrinsicEra {
* @description Returns the item as a [[MortalEra]]
*/
public get asMortalEra (): MortalEra {
assert(this.isMortalEra, `Cannot convert '${this.type}' via asMortalEra`);
assert(this.isMortalEra, () => `Cannot convert '${this.type}' via asMortalEra`);
return this.value as MortalEra;
}
@@ -6,7 +6,7 @@ import type { Address, Balance, Call, Index } from '../../interfaces/runtime';
import type { ExtrinsicPayloadValue, IExtrinsicSignature, IKeyringPair, Registry, SignatureOptions } from '../../types';
import type { ExtrinsicSignatureOptions } from '../types';
import { assert, isU8a, u8aConcat, u8aToHex } from '@polkadot/util';
import { assert, isU8a, stringify, u8aConcat, u8aToHex } from '@polkadot/util';
import { Compact } from '../../codec/Compact';
import { Enum } from '../../codec/Enum';
@@ -155,7 +155,7 @@ export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSig
* @description Generate a payload and applies the signature from a keypair
*/
public sign (method: Call, account: IKeyringPair, options: SignatureOptions): IExtrinsicSignature {
assert(account && account.addressRaw, `Expected a valid keypair for signing, found ${JSON.stringify(account)}`);
assert(account && account.addressRaw, () => `Expected a valid keypair for signing, found ${stringify(account)}`);
const signer = toAddress(this.registry, account.addressRaw);
const payload = this.createPayload(method, options);
@@ -168,7 +168,7 @@ export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSig
* @description Generate a payload and applies a fake signature
*/
public signFake (method: Call, address: Address | Uint8Array | string, options: SignatureOptions): IExtrinsicSignature {
assert(address, `Expected a valid address for signing, found ${JSON.stringify(address)}`);
assert(address, () => `Expected a valid address for signing, found ${stringify(address)}`);
const signer = toAddress(this.registry, address);
const payload = this.createPayload(method, options);
+2 -6
View File
@@ -35,15 +35,11 @@ export class GenericAccountId extends U8aFixed {
const decoded = decodeAccountId(value);
// Part of stream containing >= 32 bytes or a all empty (defaults)
assert(decoded.length >= 32 || !decoded.some((b) => b), `Invalid AccountId provided, expected 32 bytes, found ${decoded.length}`);
assert(decoded.length >= 32 || !decoded.some((b) => b), () => `Invalid AccountId provided, expected 32 bytes, found ${decoded.length}`);
super(registry, decoded, 256);
}
public static encode (value: Uint8Array, ss58Format?: number): string {
return encodeAddress(value, ss58Format);
}
/**
* @description Compares the value of the input to see if there is a match
*/
@@ -69,7 +65,7 @@ export class GenericAccountId extends U8aFixed {
* @description Returns the string representation of the value
*/
public toString (): string {
return GenericAccountId.encode(this, this.registry.chainSS58);
return encodeAddress(this, this.registry.chainSS58);
}
/**
+1 -1
View File
@@ -16,7 +16,7 @@ describe('Call', (): void => {
it('handles decoding correctly (bare)', (): void => {
expect(
new Call(registry, {
args: [],
args: ['0x0000000000000000000000000000000000000000000000000000000000000000', 0, 0],
callIndex: [6, 1] // balances.setBalance
}).toU8a()
).toEqual(
+1 -1
View File
@@ -17,7 +17,7 @@ function decodeBitVecU8a (value?: Uint8Array): Uint8Array {
const [offset, length] = compactFromU8a(value);
const total = offset + Math.ceil(length.toNumber() / 8);
assert(total <= value.length, `BitVec: required length less than remainder, expected at least ${total}, found ${value.length}`);
assert(total <= value.length, () => `BitVec: required length less than remainder, expected at least ${total}, found ${value.length}`);
return value.subarray(offset, total);
}
+2 -2
View File
@@ -20,8 +20,8 @@ function decodeBytesU8a (value: Uint8Array): Uint8Array {
const [offset, length] = compactFromU8a(value);
const total = offset + length.toNumber();
assert(length.lten(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}`);
assert(length.lten(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}`);
return value.subarray(offset, total);
}
+2 -2
View File
@@ -28,8 +28,8 @@ function decodeText (value?: null | Text | string | AnyU8a | { toString: () => s
const [offset, length] = compactFromU8a(value);
const total = offset + length.toNumber();
assert(length.lten(MAX_LENGTH), `Text length ${length.toString()} exceeds ${MAX_LENGTH}`);
assert(total <= value.length, `Text: required length less than remainder, expected at least ${total}, found ${value.length}`);
assert(length.lten(MAX_LENGTH), () => `Text length ${length.toString()} exceeds ${MAX_LENGTH}`);
assert(total <= value.length, () => `Text: required length less than remainder, expected at least ${total}, found ${value.length}`);
return u8aToString(value.subarray(offset, total));
}