Allow construction of HashMap (#1955)

* Allow construction of HashMap

* WIP... add Map to codec, extend BTreeMap & HashMap from it

* Rework various map tests

* registry.createClass

* createClass in tests
This commit is contained in:
Jaco Greeff
2020-02-26 21:30:38 +01:00
committed by GitHub
parent e31966496b
commit 85ae6f949b
38 changed files with 467 additions and 351 deletions
@@ -9,12 +9,12 @@ import { Observable, of } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { ENUMSET_SIZE } from '@polkadot/types/generic/AccountIndex';
import { ClassOf, Option, Vec, createType } from '@polkadot/types';
import { Option, Vec, createType } from '@polkadot/types';
import { memo } from '../util';
function queryEnumSet (api: ApiInterfaceRx, _accountIndex: AccountIndex | string): Observable<AccountId | undefined> {
const accountIndex = _accountIndex instanceof ClassOf(api.registry, 'AccountIndex')
const accountIndex = _accountIndex instanceof api.registry.createClass('AccountIndex')
? _accountIndex
: createType(api.registry, 'AccountIndex', _accountIndex);
+1 -2
View File
@@ -10,7 +10,6 @@ import { AddressOrPair, SignerOptions, SubmittableExtrinsic, SubmittablePaymentR
import { Observable, combineLatest, of } from 'rxjs';
import { first, map, mapTo, mergeMap, switchMap, tap } from 'rxjs/operators';
import { ClassOf } from '@polkadot/types';
import { assert, isBn, isFunction, isNumber, isUndefined } from '@polkadot/util';
import { filterEvents, isKeyringPair } from '../util';
@@ -32,7 +31,7 @@ const DEFAULT_MORTAL_LENGTH = 5 * ONE_MINUTE;
export default function createClass <ApiType extends ApiTypes> ({ api, apiType, decorateMethod }: SubmittableOptions<ApiType>): Constructor<SubmittableExtrinsic<ApiType>> {
// an instance of the base extrinsic for us to extend
const Extrinsic = ClassOf(api.registry, 'Extrinsic');
const Extrinsic = api.registry.createClass('Extrinsic');
return class Submittable extends Extrinsic implements SubmittableExtrinsic<ApiType> {
readonly #ignoreStatusCb: boolean;
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ClassOf, TypeRegistry } from '@polkadot/types/create';
import { TypeRegistry } from '@polkadot/types/create';
import { u8aToHex } from '@polkadot/util';
import Decorated from './Decorated';
@@ -40,7 +40,7 @@ describe('Decorated', () => {
});
it('should return constants with the correct type and value', (): void => {
expect(decorated.consts.democracy.cooloffPeriod).toBeInstanceOf(ClassOf(registry, 'BlockNumber'));
expect(decorated.consts.democracy.cooloffPeriod).toBeInstanceOf(registry.createClass('BlockNumber'));
expect(decorated.consts.democracy.cooloffPeriod.toHex()).toEqual('0x000c4e00');
});
});
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ClassOf, Metadata, TypeRegistry } from '@polkadot/types';
import { Metadata, TypeRegistry } from '@polkadot/types';
import rpcMetadata from '../../../Metadata/static';
import fromMetadata from '../fromMetadata';
@@ -14,7 +14,7 @@ const consts = fromMetadata(registry, metadata);
describe('fromMetadata', (): void => {
it('should return constants with the correct type and value', (): void => {
expect(consts.democracy.cooloffPeriod).toBeInstanceOf(ClassOf(registry, 'BlockNumber'));
expect(consts.democracy.cooloffPeriod).toBeInstanceOf(registry.createClass('BlockNumber'));
// 3 second blocks, 28 days
expect(consts.democracy.cooloffPeriod.toNumber()).toEqual(28 * 24 * 60 * (60 / 3));
});
+2
View File
@@ -38,6 +38,7 @@ function tsExport (definitions: object, def: TypeDef, imports: TypeImports): str
const tsBTreeMap = tsExport;
const tsBTreeSet = tsExport;
const tsCompact = tsExport;
const tsHashMap = tsExport;
const tsOption = tsExport;
const tsPlain = tsExport;
const tsTuple = tsExport;
@@ -156,6 +157,7 @@ function generateInterfaces (definitions: object, { types }: { types: Record<str
[TypeDefInfo.BTreeSet]: tsBTreeSet,
[TypeDefInfo.Compact]: tsCompact,
[TypeDefInfo.Enum]: tsEnum,
[TypeDefInfo.HashMap]: tsHashMap,
[TypeDefInfo.Int]: tsInt,
[TypeDefInfo.Linkage]: errorUnhandled,
[TypeDefInfo.Null]: errorUnhandled,
+2 -2
View File
@@ -5,7 +5,7 @@
import { TypeDef, TypeDefInfo } from '@polkadot/types/create/types';
import { Constructor, Registry } from '@polkadot/types/types';
import { ClassOf, ClassOfUnsafe, getTypeDef } from '@polkadot/types/create';
import { ClassOfUnsafe, getTypeDef } from '@polkadot/types/create';
import AbstractInt from '@polkadot/types/codec/AbstractInt';
import Compact from '@polkadot/types/codec/Compact';
import Enum from '@polkadot/types/codec/Enum';
@@ -118,7 +118,7 @@ export function getSimilarTypes (definitions: object, registry: Registry, _type:
possibleTypes.push('Address', 'AccountId', 'AccountIndex', 'string', 'Uint8Array');
} else if (isChildClass(GenericAccountId, Clazz)) {
possibleTypes.push('string', 'Uint8Array');
} else if (isChildClass(ClassOf(registry, 'bool'), Clazz)) {
} else if (isChildClass(registry.createClass('bool'), Clazz)) {
possibleTypes.push('boolean', 'Uint8Array');
} else if (isChildClass(Null, Clazz)) {
possibleTypes.push('null');
+26 -1
View File
@@ -97,6 +97,14 @@ function formatCompact (inner: string): string {
return paramsNotation('Compact', inner);
}
/**
* Given the inner `K` & `V`, return a `BTreeMap<K, V>` string
*/
/** @internal */
function formatHashMap (key: string, val: string): string {
return `HashMap<${key}, ${val}>`;
}
/**
* Given the inner `O` & `E`, return a `Result<O, E>` string
*/
@@ -150,13 +158,16 @@ export function formatType (definitions: object, type: string | TypeDef, imports
setImports(definitions, imports, [typeDef.type]);
// FIXME Swap to Record<TypeDefInfo, fn> to check all types
switch (typeDef.info) {
case TypeDefInfo.Compact: {
setImports(definitions, imports, ['Compact']);
return formatCompact(formatType(definitions, (typeDef.sub as TypeDef).type, imports));
}
case TypeDefInfo.Option: {
setImports(definitions, imports, ['Option']);
return formatOption(formatType(definitions, (typeDef.sub as TypeDef).type, imports));
}
case TypeDefInfo.Plain: {
@@ -164,6 +175,7 @@ export function formatType (definitions: object, type: string | TypeDef, imports
}
case TypeDefInfo.Vec: {
setImports(definitions, imports, ['Vec']);
return formatVec(formatType(definitions, (typeDef.sub as TypeDef).type, imports));
}
case TypeDefInfo.Tuple: {
@@ -190,21 +202,34 @@ export function formatType (definitions: object, type: string | TypeDef, imports
}
case TypeDefInfo.BTreeMap: {
setImports(definitions, imports, ['BTreeMap']);
const [keyDef, valDef] = (typeDef.sub as TypeDef[]);
return formatBTreeMap(formatType(definitions, keyDef.type, imports), formatType(definitions, valDef.type, imports));
}
case TypeDefInfo.BTreeSet: {
setImports(definitions, imports, ['BTreeSet']);
const valDef = typeDef.sub as TypeDef;
return formatBTreeSet(formatType(definitions, valDef.type, imports));
}
case TypeDefInfo.HashMap: {
setImports(definitions, imports, ['HashMap']);
const [keyDef, valDef] = (typeDef.sub as TypeDef[]);
return formatHashMap(formatType(definitions, keyDef.type, imports), formatType(definitions, valDef.type, imports));
}
case TypeDefInfo.Result: {
setImports(definitions, imports, ['Result']);
const [okDef, errorDef] = (typeDef.sub as TypeDef[]);
return formatResult(formatType(definitions, okDef.type, imports), formatType(definitions, errorDef.type, imports));
}
default: {
throw new Error(`Cannot format ${type}.`);
throw new Error(`Cannot format ${JSON.stringify(type)}`);
}
}
}
+6 -62
View File
@@ -6,72 +6,16 @@ import { TypeRegistry } from '../create';
import Text from '../primitive/Text';
import U32 from '../primitive/U32';
import Struct from './Struct';
import { CodecTo } from '../types';
import BTreeMap from './BTreeMap';
const registry = new TypeRegistry();
const mockU32TextMap = new Map<Text, U32>();
mockU32TextMap.set(new Text(registry, 'bazzing'), new U32(registry, 69));
const mockU32TextMapString = '{"bazzing":69}';
const mockU32TextMapObject = { bazzing: 69 };
const mockU32TextMapHexString = '0x041c62617a7a696e6745000000';
const mockU32TextMapUint8Array = Uint8Array.from([4, 28, 98, 97, 122, 122, 105, 110, 103, 69, 0, 0, 0]);
const mockU32U32Map = new Map<U32, U32>();
mockU32U32Map.set(new U32(registry, 1), new U32(registry, 2));
mockU32U32Map.set(new U32(registry, 23), new U32(registry, 24));
mockU32U32Map.set(new U32(registry, 28), new U32(registry, 30));
mockU32U32Map.set(new U32(registry, 45), new U32(registry, 80));
const mockU32U32MapString = '{"1":2,"23":24,"28":30,"45":80}';
const mockU32U32MapObject = { 1: 2, 23: 24, 28: 30, 45: 80 };
const mockU32U32MapHexString = '0x10043102000000083233180000000832381e00000008343550000000';
const mockU32U32MapUint8Array = Uint8Array.from([16, 4, 49, 2, 0, 0, 0, 8, 50, 51, 24, 0, 0, 0, 8, 50, 56, 30, 0, 0, 0, 8, 52, 53, 80, 0, 0, 0]);
const mockU32TextMap = new Map<Text, U32>();
mockU32TextMap.set(new Text(registry, 'bazzing'), new U32(registry, 69));
describe('BTreeMap', (): void => {
describe('decoding', (): void => {
const testDecode = (type: string, input: any, output: string): void =>
it(`can decode from ${type}`, (): void => {
const s = new BTreeMap(registry, Text, U32, input);
expect(s.toString()).toBe(output);
});
testDecode('map', mockU32TextMap, mockU32TextMapString);
testDecode('hex', mockU32TextMapHexString, mockU32TextMapString);
testDecode('Uint8Array', mockU32TextMapUint8Array, mockU32TextMapString);
testDecode('map', mockU32U32Map, mockU32U32MapString);
testDecode('hex', mockU32U32MapHexString, mockU32U32MapString);
testDecode('Uint8Array', mockU32U32MapUint8Array, mockU32U32MapString);
});
describe('encoding', (): void => {
const testEncode = (to: CodecTo, expected: any): void =>
it(`can encode ${to}`, (): void => {
const s = new BTreeMap(registry, Text, U32, mockU32TextMap);
expect(s[to]()).toEqual(expected);
});
testEncode('toHex', mockU32TextMapHexString);
testEncode('toJSON', mockU32TextMapObject);
testEncode('toU8a', mockU32TextMapUint8Array);
testEncode('toString', mockU32TextMapString);
});
describe('encoding muple values', (): void => {
const testEncode = (to: CodecTo, expected: any): void =>
it(`can encode ${to}`, (): void => {
const s = new BTreeMap(registry, Text, U32, mockU32U32Map);
expect(s[to]()).toEqual(expected);
});
testEncode('toHex', mockU32U32MapHexString);
testEncode('toJSON', mockU32U32MapObject);
testEncode('toU8a', mockU32U32MapUint8Array);
testEncode('toString', mockU32U32MapString);
});
it('decodes null', (): void => {
expect(
new (
@@ -83,9 +27,9 @@ describe('BTreeMap', (): void => {
it('decodes within more complicated types', (): void => {
const s = new Struct(registry, {
placeholder: U32,
value: BTreeMap.with(Text, U32)
value: 'BTreeMap<Text, U32>' as any
});
s.set('value', new BTreeMap(registry, Text, U32, mockU32TextMap));
s.set('value', new (BTreeMap.with(Text, U32))(registry, mockU32TextMap));
expect(s.toString()).toBe('{"placeholder":0,"value":{"bazzing":69}}');
});
@@ -94,7 +38,7 @@ describe('BTreeMap', (): void => {
(): BTreeMap<Text, U32> => new (
BTreeMap.with(Text, U32)
)(registry, 'ABC')
).toThrowError(/BTreeMap: cannot decode type/);
).toThrowError(/Map: cannot decode type/);
});
it('correctly encodes length', (): void => {
+5 -201
View File
@@ -2,212 +2,16 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { H256 } from '../interfaces/runtime';
import { AnyJson, Constructor, Codec, InterfaceTypes, Registry } from '../types';
import { Constructor, Codec, InterfaceTypes, Registry } from '../types';
import { isHex, hexToU8a, isObject, isU8a, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { blake2AsU8a } from '@polkadot/util-crypto';
import CodecMap from './Map';
import Compact from './Compact';
import Raw from './Raw';
import { compareMap, decodeU8a, typeToConstructor } from './utils';
/** @internal */
function decodeBTreeMapFromU8a<K extends Codec = Codec, V extends Codec = Codec> (registry: Registry, KeyClass: Constructor<K>, ValClass: Constructor<V>, u8a: Uint8Array): Map<K, V> {
const output = new Map<K, V>();
const [offset, length] = Compact.decodeU8a(u8a);
const types = [];
for (let i = 0; i < length.toNumber(); i++) {
types.push(KeyClass, ValClass);
}
const values = decodeU8a(registry, u8a.subarray(offset), types);
for (let i = 0; i < values.length; i += 2) {
output.set(values[i] as K, values[i + 1] as V);
}
return output;
}
/** @internal */
function decodeBTreeMapFromMap<K extends Codec = Codec, V extends Codec = Codec> (registry: Registry, KeyClass: Constructor<K>, ValClass: Constructor<V>, value: Map<any, any>): Map<K, V> {
const output = new Map<K, V>();
value.forEach((val: any, key: any) => {
try {
output.set(
key instanceof KeyClass
? key
: new KeyClass(registry, key),
val instanceof ValClass
? val
: new ValClass(registry, val)
);
} catch (error) {
console.error('Failed to decode BTreeMap key or value:', error.message);
throw error;
}
});
return output;
}
/**
* Decode input to pass into constructor.
*
* @param KeyClass - Type of the map key
* @param ValClass - Type of the map value
* @param value - Value to decode, one of:
* - null
* - undefined
* - hex
* - Uint8Array
* - Map<any, any>, where both key and value types are either
* constructors or decodeable values for their types.
* @param jsonMap
* @internal
*/
function decodeBTreeMap<K extends Codec = Codec, V extends Codec = Codec> (registry: Registry, keyType: Constructor<K> | keyof InterfaceTypes, valType: Constructor<V> | keyof InterfaceTypes, value: Uint8Array | string | Map<any, any>): Map<K, V> {
const KeyClass = typeToConstructor(registry, keyType);
const ValClass = typeToConstructor(registry, valType);
if (!value) {
return new Map<K, V>();
} else if (isHex(value)) {
return decodeBTreeMap(registry, KeyClass, ValClass, hexToU8a(value));
} else if (isU8a(value)) {
return decodeBTreeMapFromU8a<K, V>(registry, KeyClass, ValClass, u8aToU8a(value));
} else if (value instanceof Map) {
return decodeBTreeMapFromMap<K, V>(registry, KeyClass, ValClass, value);
} else if (isObject(value)) {
return decodeBTreeMapFromMap<K, V>(registry, KeyClass, ValClass, new Map(Object.entries(value)));
}
throw new Error('BTreeMap: cannot decode type');
}
export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec> extends Map<K, V> implements Codec {
public readonly registry: Registry;
readonly #KeyClass: Constructor<K>;
readonly #ValClass: Constructor<V>;
constructor (registry: Registry, keyType: Constructor<K> | keyof InterfaceTypes, valType: Constructor<V> | keyof InterfaceTypes, rawValue: any) {
super(decodeBTreeMap(registry, keyType, valType, rawValue));
this.registry = registry;
this.#KeyClass = typeToConstructor(registry, keyType);
this.#ValClass = typeToConstructor(registry, valType);
}
public static with<K extends Codec, V extends Codec> (keyType: Constructor<K> | keyof InterfaceTypes, valType: Constructor<V> | keyof InterfaceTypes): Constructor<BTreeMap<K, V>> {
export default class BTreeMap<K extends Codec = Codec, V extends Codec = Codec> extends CodecMap<K, V> {
public static with<K extends Codec, V extends Codec> (keyType: Constructor<K> | keyof InterfaceTypes, valType: Constructor<V> | keyof InterfaceTypes): Constructor<CodecMap<K, V>> {
return class extends BTreeMap<K, V> {
constructor (registry: Registry, value?: any) {
super(registry, keyType, valType, value);
super(registry, 'BTreeMap', keyType, valType, value);
}
};
}
/**
* @description The length of the value when encoded as a Uint8Array
*/
public get encodedLength (): number {
let len = Compact.encodeU8a(this.size).length;
this.forEach((v: V, k: K) => {
len += v.encodedLength + k.encodedLength;
});
return len;
}
/**
* @description Returns a hash of the value
*/
public get hash (): H256 {
return new Raw(this.registry, blake2AsU8a(this.toU8a(), 256));
}
/**
* @description Checks if the value is an empty value
*/
public get isEmpty (): boolean {
return this.size === 0;
}
/**
* @description Compares the value of the input to see if there is a match
*/
public eq (other?: any): boolean {
return compareMap(this, other);
}
/**
* @description Returns a hex string representation of the value. isLe returns a LE (number-only) representation
*/
public toHex (): string {
return u8aToHex(this.toU8a());
}
/**
* @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information
*/
public toHuman (isExtended?: boolean): AnyJson {
const json: any = {};
this.forEach((v: V, k: K) => {
json[k.toString()] = v.toHuman(isExtended);
});
return json;
}
/**
* @description Converts the Object to JSON, typically used for RPC transfers
*/
public toJSON (): AnyJson {
const json: any = {};
this.forEach((v: V, k: K) => {
json[k.toString()] = v.toJSON();
});
return json;
}
/**
* @description Returns the base runtime type name for this instance
*/
public toRawType (): string {
return `BTreeMap<${new this.#KeyClass(this.registry).toRawType()},${new this.#ValClass(this.registry).toRawType()}>`;
}
/**
* @description Returns the string representation of the value
*/
public toString (): string {
return JSON.stringify(this.toJSON());
}
/**
* @description Encodes the value as a Uint8Array as per the SCALE specifications
* @param isBare true when the value has none of the type-specific prefixes (internal)
*/
public toU8a (isBare?: boolean): Uint8Array {
const encoded = new Array<Uint8Array>();
if (!isBare) {
encoded.push(Compact.encodeU8a(this.size));
}
this.forEach((v: V, k: K) => {
encoded.push(k.toU8a(isBare), v.toU8a(isBare));
});
return u8aConcat(...encoded);
}
}
+9 -12
View File
@@ -13,7 +13,7 @@ import Raw from './Raw';
import { compareSet, decodeU8a, typeToConstructor } from './utils';
/** @internal */
function decodeBTreeSetFromU8a<V extends Codec = Codec> (registry: Registry, ValClass: Constructor<V>, u8a: Uint8Array): Set<V> {
function decodeSetFromU8a<V extends Codec = Codec> (registry: Registry, ValClass: Constructor<V>, u8a: Uint8Array): Set<V> {
const output = new Set<V>();
const [offset, length] = Compact.decodeU8a(u8a);
const types = [];
@@ -32,19 +32,16 @@ function decodeBTreeSetFromU8a<V extends Codec = Codec> (registry: Registry, Val
}
/** @internal */
function decodeBTreeSetFromSet<V extends Codec = Codec> (registry: Registry, ValClass: Constructor<V>, value: Set<any>): Set<V> {
function decodeSetFromSet<V extends Codec = Codec> (registry: Registry, ValClass: Constructor<V>, value: Set<any>): Set<V> {
const output = new Set<V>();
value.forEach((v: any) => {
let val;
value.forEach((val: any) => {
try {
val = (v instanceof ValClass) ? v : new ValClass(registry, v);
output.add((val instanceof ValClass) ? val : new ValClass(registry, val));
} catch (error) {
console.error('Failed to decode BTreeSet key or value:', error.message);
throw error;
}
output.add(val);
});
return output;
@@ -64,7 +61,7 @@ function decodeBTreeSetFromSet<V extends Codec = Codec> (registry: Registry, Val
* @param jsonSet
* @internal
*/
function decodeBTreeSet<V extends Codec = Codec> (registry: Registry, valType: Constructor<V> | keyof InterfaceTypes, value: Uint8Array | string | Set<any>): Set<V> {
function decodeSet<V extends Codec = Codec> (registry: Registry, valType: Constructor<V> | keyof InterfaceTypes, value: Uint8Array | string | Set<any>): Set<V> {
if (!value) {
return new Set<V>();
}
@@ -72,11 +69,11 @@ function decodeBTreeSet<V extends Codec = Codec> (registry: Registry, valType: C
const ValClass = typeToConstructor(registry, valType);
if (isHex(value)) {
return decodeBTreeSet(registry, ValClass, hexToU8a(value));
return decodeSet(registry, ValClass, hexToU8a(value));
} else if (isU8a(value)) {
return decodeBTreeSetFromU8a<V>(registry, ValClass, u8aToU8a(value));
return decodeSetFromU8a<V>(registry, ValClass, u8aToU8a(value));
} else if (value instanceof Set) {
return decodeBTreeSetFromSet<V>(registry, ValClass, value);
return decodeSetFromSet<V>(registry, ValClass, value);
}
throw new Error('BTreeSet: cannot decode type');
@@ -88,7 +85,7 @@ export default class BTreeSet<V extends Codec = Codec> extends Set<V> implements
readonly #ValClass: Constructor<V>;
constructor (registry: Registry, valType: Constructor<V> | keyof InterfaceTypes, rawValue: any) {
super(decodeBTreeSet(registry, valType, rawValue));
super(decodeSet(registry, valType, rawValue));
this.registry = registry;
this.#ValClass = typeToConstructor(registry, valType);
+3 -3
View File
@@ -4,7 +4,7 @@
import BN from 'bn.js';
import { ClassOf, TypeRegistry } from '../create';
import { TypeRegistry } from '../create';
import Moment from './Date';
import U32 from '../primitive/U32';
import Compact from './Compact';
@@ -115,7 +115,7 @@ describe('Compact', (): void => {
it('has the correct bitLength for constructor values (BlockNumber)', (): void => {
expect(
new (Compact.with(ClassOf(registry, 'BlockNumber')))(registry, 0xfffffff9).bitLength()
new (Compact.with(registry.createClass('BlockNumber')))(registry, 0xfffffff9).bitLength()
).toEqual(32);
});
@@ -127,7 +127,7 @@ describe('Compact', (): void => {
it('has the correct encodedLength for constructor values (class BlockNumber)', (): void => {
expect(
new (Compact.with(ClassOf(registry, 'BlockNumber')))(registry, 0xfffffff9).encodedLength
new (Compact.with(registry.createClass('BlockNumber')))(registry, 0xfffffff9).encodedLength
).toEqual(5);
});
+1 -1
View File
@@ -8,7 +8,7 @@ import BN from 'bn.js';
import { compactAddLength, compactFromU8a, compactStripLength, compactToU8a, isBigInt, isBn, isNumber, isString } from '@polkadot/util';
import { DEFAULT_BITLENGTH } from '@polkadot/util/compact/defaults';
import { typeToConstructor } from './utils';
import typeToConstructor from './utils/typeToConstructor';
import { UIntBitLength } from './AbstractInt';
import Base from './Base';
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2017-2020 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { TypeRegistry } from '../create';
import Text from '../primitive/Text';
import U32 from '../primitive/U32';
import Struct from './Struct';
import HashMap from './HashMap';
const registry = new TypeRegistry();
describe('HashMap', (): void => {
it('generates sane toRawTypes', (): void => {
expect(new (HashMap.with(Text, U32))(registry).toRawType()).toBe('HashMap<Text,u32>');
expect(new (HashMap.with(Text, Text))(registry).toRawType()).toBe('HashMap<Text,Text>');
expect(new (HashMap.with(Text, Struct.with({ a: U32, b: Text })))(registry).toRawType())
.toBe('HashMap<Text,{"a":"u32","b":"Text"}>');
});
});
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2017-2020 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Constructor, Codec, InterfaceTypes, Registry } from '../types';
import CodecMap from './Map';
export default class HashMap<K extends Codec = Codec, V extends Codec = Codec> extends CodecMap<K, V> {
public static with<K extends Codec, V extends Codec> (keyType: Constructor<K> | keyof InterfaceTypes, valType: Constructor<V> | keyof InterfaceTypes): Constructor<CodecMap<K, V>> {
return class extends HashMap<K, V> {
constructor (registry: Registry, value?: any) {
super(registry, 'HashMap', keyType, valType, value);
}
};
}
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright 2017-2020 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { TypeRegistry } from '../create';
import Text from '../primitive/Text';
import U32 from '../primitive/U32';
import { CodecTo } from '../types';
import CodecMap from './Map';
const registry = new TypeRegistry();
const mockU32TextMap = new Map<Text, U32>();
mockU32TextMap.set(new Text(registry, 'bazzing'), new U32(registry, 69));
const mockU32TextMapString = '{"bazzing":69}';
const mockU32TextMapObject = { bazzing: 69 };
const mockU32TextMapHexString = '0x041c62617a7a696e6745000000';
const mockU32TextMapUint8Array = Uint8Array.from([4, 28, 98, 97, 122, 122, 105, 110, 103, 69, 0, 0, 0]);
const mockU32U32Map = new Map<U32, U32>();
mockU32U32Map.set(new U32(registry, 1), new U32(registry, 2));
mockU32U32Map.set(new U32(registry, 23), new U32(registry, 24));
mockU32U32Map.set(new U32(registry, 28), new U32(registry, 30));
mockU32U32Map.set(new U32(registry, 45), new U32(registry, 80));
const mockU32U32MapString = '{"1":2,"23":24,"28":30,"45":80}';
const mockU32U32MapObject = { 1: 2, 23: 24, 28: 30, 45: 80 };
const mockU32U32MapHexString = '0x10043102000000083233180000000832381e00000008343550000000';
const mockU32U32MapUint8Array = Uint8Array.from([16, 4, 49, 2, 0, 0, 0, 8, 50, 51, 24, 0, 0, 0, 8, 50, 56, 30, 0, 0, 0, 8, 52, 53, 80, 0, 0, 0]);
describe('CodecMap', (): void => {
describe('decoding', (): void => {
const testDecode = (type: string, input: any, output: string): void =>
it(`can decode from ${type}`, (): void => {
const s = new CodecMap(registry, 'HashMap', Text, U32, input);
expect(s.toString()).toBe(output);
});
testDecode('map', mockU32TextMap, mockU32TextMapString);
testDecode('hex', mockU32TextMapHexString, mockU32TextMapString);
testDecode('Uint8Array', mockU32TextMapUint8Array, mockU32TextMapString);
testDecode('map', mockU32U32Map, mockU32U32MapString);
testDecode('hex', mockU32U32MapHexString, mockU32U32MapString);
testDecode('Uint8Array', mockU32U32MapUint8Array, mockU32U32MapString);
});
describe('encoding', (): void => {
const testEncode = (to: CodecTo, expected: any): void =>
it(`can encode ${to}`, (): void => {
const s = new CodecMap(registry, 'BTreeMap', Text, U32, mockU32TextMap);
expect(s[to]()).toEqual(expected);
});
testEncode('toHex', mockU32TextMapHexString);
testEncode('toJSON', mockU32TextMapObject);
testEncode('toU8a', mockU32TextMapUint8Array);
testEncode('toString', mockU32TextMapString);
});
describe('encoding muple values', (): void => {
const testEncode = (to: CodecTo, expected: any): void =>
it(`can encode ${to}`, (): void => {
const s = new CodecMap(registry, 'BTreeMap', Text, U32, mockU32U32Map);
expect(s[to]()).toEqual(expected);
});
testEncode('toHex', mockU32U32MapHexString);
testEncode('toJSON', mockU32U32MapObject);
testEncode('toU8a', mockU32U32MapUint8Array);
testEncode('toString', mockU32U32MapString);
});
});
+210
View File
@@ -0,0 +1,210 @@
// Copyright 2017-2020 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { H256 } from '../interfaces/runtime';
import { AnyJson, Constructor, Codec, InterfaceTypes, Registry } from '../types';
import { isHex, hexToU8a, isObject, isU8a, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { blake2AsU8a } from '@polkadot/util-crypto';
import Compact from './Compact';
import Raw from './Raw';
import compareMap from './utils/compareMap';
import decodeU8a from './utils/decodeU8a';
import typeToConstructor from './utils/typeToConstructor';
/** @internal */
function decodeMapFromU8a<K extends Codec = Codec, V extends Codec = Codec> (registry: Registry, KeyClass: Constructor<K>, ValClass: Constructor<V>, u8a: Uint8Array): Map<K, V> {
const output = new Map<K, V>();
const [offset, length] = Compact.decodeU8a(u8a);
const types = [];
for (let i = 0; i < length.toNumber(); i++) {
types.push(KeyClass, ValClass);
}
const values = decodeU8a(registry, u8a.subarray(offset), types);
for (let i = 0; i < values.length; i += 2) {
output.set(values[i] as K, values[i + 1] as V);
}
return output;
}
/** @internal */
function decodeMapFromMap<K extends Codec = Codec, V extends Codec = Codec> (registry: Registry, KeyClass: Constructor<K>, ValClass: Constructor<V>, value: Map<any, any>): Map<K, V> {
const output = new Map<K, V>();
value.forEach((val: any, key: any) => {
try {
output.set(
key instanceof KeyClass
? key
: new KeyClass(registry, key),
val instanceof ValClass
? val
: new ValClass(registry, val)
);
} catch (error) {
console.error('Failed to decode Map key or value:', error.message);
throw error;
}
});
return output;
}
/**
* Decode input to pass into constructor.
*
* @param KeyClass - Type of the map key
* @param ValClass - Type of the map value
* @param value - Value to decode, one of:
* - null
* - undefined
* - hex
* - Uint8Array
* - Map<any, any>, where both key and value types are either
* constructors or decodeable values for their types.
* @param jsonMap
* @internal
*/
function decodeMap<K extends Codec = Codec, V extends Codec = Codec> (registry: Registry, keyType: Constructor<K> | keyof InterfaceTypes, valType: Constructor<V> | keyof InterfaceTypes, value: Uint8Array | string | Map<any, any>): Map<K, V> {
const KeyClass = typeToConstructor(registry, keyType);
const ValClass = typeToConstructor(registry, valType);
if (!value) {
return new Map<K, V>();
} else if (isHex(value)) {
return decodeMap(registry, KeyClass, ValClass, hexToU8a(value));
} else if (isU8a(value)) {
return decodeMapFromU8a<K, V>(registry, KeyClass, ValClass, u8aToU8a(value));
} else if (value instanceof Map) {
return decodeMapFromMap<K, V>(registry, KeyClass, ValClass, value);
} else if (isObject(value)) {
return decodeMapFromMap<K, V>(registry, KeyClass, ValClass, new Map(Object.entries(value)));
}
throw new Error('Map: cannot decode type');
}
export default class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends Map<K, V> implements Codec {
public readonly registry: Registry;
readonly #KeyClass: Constructor<K>;
readonly #ValClass: Constructor<V>;
readonly #type: string;
constructor (registry: Registry, type: 'BTreeMap' | 'HashMap', keyType: Constructor<K> | keyof InterfaceTypes, valType: Constructor<V> | keyof InterfaceTypes, rawValue: any) {
super(decodeMap(registry, keyType, valType, rawValue));
this.registry = registry;
this.#KeyClass = typeToConstructor(registry, keyType);
this.#ValClass = typeToConstructor(registry, valType);
this.#type = type;
}
/**
* @description The length of the value when encoded as a Uint8Array
*/
public get encodedLength (): number {
let len = Compact.encodeU8a(this.size).length;
this.forEach((v: V, k: K) => {
len += v.encodedLength + k.encodedLength;
});
return len;
}
/**
* @description Returns a hash of the value
*/
public get hash (): H256 {
return new Raw(this.registry, blake2AsU8a(this.toU8a(), 256));
}
/**
* @description Checks if the value is an empty value
*/
public get isEmpty (): boolean {
return this.size === 0;
}
/**
* @description Compares the value of the input to see if there is a match
*/
public eq (other?: any): boolean {
return compareMap(this, other);
}
/**
* @description Returns a hex string representation of the value. isLe returns a LE (number-only) representation
*/
public toHex (): string {
return u8aToHex(this.toU8a());
}
/**
* @description Converts the Object to to a human-friendly JSON, with additional fields, expansion and formatting of information
*/
public toHuman (isExtended?: boolean): AnyJson {
const json: any = {};
this.forEach((v: V, k: K) => {
json[k.toString()] = v.toHuman(isExtended);
});
return json;
}
/**
* @description Converts the Object to JSON, typically used for RPC transfers
*/
public toJSON (): AnyJson {
const json: any = {};
this.forEach((v: V, k: K) => {
json[k.toString()] = v.toJSON();
});
return json;
}
/**
* @description Returns the base runtime type name for this instance
*/
public toRawType (): string {
return `${this.#type}<${new this.#KeyClass(this.registry).toRawType()},${new this.#ValClass(this.registry).toRawType()}>`;
}
/**
* @description Returns the string representation of the value
*/
public toString (): string {
return JSON.stringify(this.toJSON());
}
/**
* @description Encodes the value as a Uint8Array as per the SCALE specifications
* @param isBare true when the value has none of the type-specific prefixes (internal)
*/
public toU8a (isBare?: boolean): Uint8Array {
const encoded = new Array<Uint8Array>();
if (!isBare) {
encoded.push(Compact.encodeU8a(this.size));
}
this.forEach((v: V, k: K) => {
encoded.push(k.toU8a(isBare), v.toU8a(isBare));
});
return u8aConcat(...encoded);
}
}
+7 -7
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ClassOf, TypeRegistry } from '../create';
import { TypeRegistry } from '../create';
import AccountId from '../generic/AccountId';
import Text from '../primitive/Text';
import U32 from '../primitive/U32';
@@ -193,7 +193,7 @@ describe('Struct', (): void => {
// replicate https://github.com/polkadot-js/api/issues/640
expect(
new Struct(registry, {
blockNumber: ClassOf(registry, 'Option<BlockNumber>')
blockNumber: registry.createClass('Option<BlockNumber>')
}, { blockNumber: '0x0000000010abcdef' }).toString()
).toEqual('{"blockNumber":279694831}');
});
@@ -202,10 +202,10 @@ describe('Struct', (): void => {
expect(
new Struct(registry, {
accountId: AccountId,
balanceCompact: ClassOf(registry, 'Compact<Balance>'),
blockNumber: ClassOf(registry, 'BlockNumber'),
compactNumber: ClassOf(registry, 'Compact<BlockNumber>'),
optionNumber: ClassOf(registry, 'Option<BlockNumber>'),
balanceCompact: registry.createClass('Compact<Balance>'),
blockNumber: registry.createClass('BlockNumber'),
compactNumber: registry.createClass('Compact<BlockNumber>'),
optionNumber: registry.createClass('Option<BlockNumber>'),
counter: U32,
vector: Vec.with(AccountId)
}).toRawType()
@@ -223,7 +223,7 @@ describe('Struct', (): void => {
it('generates sane toRawType (via with)', (): void => {
const Type = Struct.with({
accountId: AccountId,
balance: ClassOf(registry, 'Balance')
balance: registry.createClass('Balance')
});
expect(
+6 -6
View File
@@ -9,7 +9,7 @@ import { CodecTo } from '../types';
import Metadata from '@polkadot/metadata/Metadata';
import rpcMetadata from '@polkadot/metadata/Metadata/static';
import { ClassOf, TypeRegistry } from '../create';
import { TypeRegistry } from '../create';
import Text from '../primitive/Text';
import U32 from '../primitive/U32';
import U128 from '../primitive/U128';
@@ -71,7 +71,7 @@ describe('Tuple', (): void => {
new Metadata(registry, rpcMetadata);
const test = new (Tuple.with([
ClassOf(registry, 'BlockNumber'), ClassOf(registry, 'VoteThreshold')
registry.createClass('BlockNumber'), registry.createClass('VoteThreshold')
]
))(registry, '0x6219000001');
@@ -85,8 +85,8 @@ describe('Tuple', (): void => {
it('exposes the Types (object creation)', (): void => {
const test = new Tuple(registry, {
BlockNumber: ClassOf(registry, 'BlockNumber'),
VoteThreshold: ClassOf(registry, 'VoteThreshold')
BlockNumber: registry.createClass('BlockNumber'),
VoteThreshold: registry.createClass('VoteThreshold')
}, []);
expect(test.Types).toEqual(['BlockNumber', 'VoteThreshold']);
@@ -113,13 +113,13 @@ describe('Tuple', (): void => {
describe('toRawType', (): void => {
it('generates sane value with array types', (): void => {
expect(
new Tuple(registry, [U128, ClassOf(registry, 'BlockNumber')]).toRawType()
new Tuple(registry, [U128, registry.createClass('BlockNumber')]).toRawType()
).toEqual('(u128,u32)');
});
it('generates sane value with object types', (): void => {
expect(
new Tuple(registry, { number: U128, blockNumber: ClassOf(registry, 'BlockNumber') }).toRawType()
new Tuple(registry, { number: U128, blockNumber: registry.createClass('BlockNumber') }).toRawType()
).toEqual('(u128,u32)');
});
});
+2 -3
View File
@@ -6,7 +6,6 @@ import { AnyNumber, Constructor, Registry } from '../types';
import { bnToHex, bnToU8a, formatBalance } from '@polkadot/util';
import { ClassOf } from '../create/createClass';
import AbstractInt, { DEFAULT_UINT_BITS, UIntBitLength } from './AbstractInt';
/**
@@ -53,7 +52,7 @@ export default class UInt extends AbstractInt {
*/
public toHuman (isExpanded?: boolean): any {
// FIXME we need proper expansion here
return this instanceof ClassOf(this.registry, 'Balance')
return this instanceof this.registry.createClass('Balance')
? formatBalance(this, { decimals: this.registry.chainDecimals, withSi: true, withUnit: this.registry.chainToken })
: super.toHuman(isExpanded);
}
@@ -65,7 +64,7 @@ export default class UInt extends AbstractInt {
// NOTE In the case of balances, which have a special meaning on the UI
// and can be interpreted differently, return a specific value for it so
// underlying it always matches (no matter which length it actually is)
return this instanceof ClassOf(this.registry, 'Balance')
return this instanceof this.registry.createClass('Balance')
? 'Balance'
: `u${this.bitLength()}`;
}
+1
View File
@@ -13,6 +13,7 @@ export { default as BTreeSet } from './BTreeSet';
export { default as Compact } from './Compact';
// export { default as Date } from './Date';
export { default as Enum } from './Enum';
export { default as HashMap } from './HashMap';
export { default as Option } from './Option';
export { default as Result } from './Result';
export { default as Set } from './Set';
@@ -27,6 +27,7 @@ function encodeWithParams (typeDef: Pick<TypeDef, any>, outer = typeDef.displayN
case TypeDefInfo.BTreeMap:
case TypeDefInfo.BTreeSet:
case TypeDefInfo.Compact:
case TypeDefInfo.HashMap:
case TypeDefInfo.Linkage:
case TypeDefInfo.Option:
case TypeDefInfo.Result:
@@ -122,6 +123,7 @@ const encoders: Record<TypeDefInfo, (typeDef: TypeDef) => string> = {
[TypeDefInfo.BTreeSet]: (typeDef: TypeDef): string => encodeWithParams(typeDef, 'BTreeSet'),
[TypeDefInfo.Compact]: (typeDef: TypeDef): string => encodeWithParams(typeDef, 'Compact'),
[TypeDefInfo.Enum]: (typeDef: TypeDef): string => encodeEnum(typeDef),
[TypeDefInfo.HashMap]: (typeDef: TypeDef): string => encodeWithParams(typeDef, 'HashMap'),
[TypeDefInfo.Int]: (typeDef: TypeDef): string => encodeUInt(typeDef, 'Int'),
[TypeDefInfo.Linkage]: (typeDef: TypeDef): string => encodeWithParams(typeDef, 'Linkage'),
// eslint-disable-next-line @typescript-eslint/no-unused-vars
+3 -1
View File
@@ -6,5 +6,7 @@ export { default as compareArray } from './compareArray';
export { default as compareMap } from './compareMap';
export { default as compareSet } from './compareSet';
export { default as decodeU8a } from './decodeU8a';
export { default as mapToTypeMap } from './mapToTypeMap';
export { default as typeToConstructor } from './typeToConstructor';
export * from './encodeTypes';
export * from './mapToTypeMap';
+3 -13
View File
@@ -2,24 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Codec, Constructor, InterfaceTypes, Registry } from '../../types';
import { Constructor, InterfaceTypes, Registry } from '../../types';
import { isString } from '@polkadot/util';
import { ClassOf } from '../../create/createClass';
export function typeToConstructor <T = Codec> (registry: Registry, type: keyof InterfaceTypes | Constructor<T>): Constructor<T> {
return (
isString(type)
? ClassOf(registry, type)
: type
) as Constructor<T>;
}
import typeToConstructor from './typeToConstructor';
/**
* @description takes an input map of the form `{ [string]: string | Constructor }` and returns a map of `{ [string]: Constructor }`
*/
export function mapToTypeMap (registry: Registry, input: Record<string, keyof InterfaceTypes | Constructor>): Record<string, Constructor> {
export default function mapToTypeMap (registry: Registry, input: Record<string, keyof InterfaceTypes | Constructor>): Record<string, Constructor> {
return Object
.entries(input)
.reduce((output: Record<string, Constructor>, [key, type]): Record<string, Constructor> => {
@@ -0,0 +1,15 @@
// Copyright 2017-2020 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Codec, Constructor, InterfaceTypes, Registry } from '../../types';
import { isString } from '@polkadot/util';
export default function typeToConstructor <T = Codec> (registry: Registry, type: keyof InterfaceTypes | Constructor<T>): Constructor<T> {
return (
isString(type)
? registry.createClass(type)
: type
) as Constructor<T>;
}
+12 -8
View File
@@ -12,6 +12,7 @@ import BTreeMap from '../codec/BTreeMap';
import BTreeSet from '../codec/BTreeSet';
import Compact from '../codec/Compact';
import Enum from '../codec/Enum';
import HashMap from '../codec/HashMap';
import Int from '../codec/Int';
import Option from '../codec/Option';
import Result from '../codec/Result';
@@ -83,13 +84,14 @@ function createInt ({ displayName, length }: TypeDef, Clazz: typeof Int | typeof
return Clazz.with(length as UIntBitLength, displayName);
}
const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => Constructor> = {
[TypeDefInfo.BTreeMap]: (registry: Registry, value: TypeDef): Constructor => {
const [keyType, valueType] = getTypeClassArray(value);
function createHashMap (value: TypeDef, Clazz: typeof BTreeMap | typeof HashMap): Constructor {
const [keyType, valueType] = getTypeClassArray(value);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return BTreeMap.with(keyType, valueType);
},
return Clazz.with(keyType, valueType);
}
const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => Constructor> = {
[TypeDefInfo.BTreeMap]: (registry: Registry, value: TypeDef): Constructor => createHashMap(value, BTreeMap),
[TypeDefInfo.BTreeSet]: (registry: Registry, value: TypeDef): Constructor => BTreeSet.with(getSubType(value)),
@@ -97,6 +99,8 @@ const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => C
[TypeDefInfo.Enum]: (registry: Registry, value: TypeDef): Constructor => Enum.with(getTypeClassMap(value)),
[TypeDefInfo.HashMap]: (registry: Registry, value: TypeDef): Constructor => createHashMap(value, HashMap),
[TypeDefInfo.Int]: (registry: Registry, value: TypeDef): Constructor => createInt(value, Int),
// We have circular deps between Linkage & Struct
@@ -112,7 +116,7 @@ const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => C
},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
[TypeDefInfo.Null]: (registry: Registry, _: TypeDef): Constructor => ClassOf(registry, 'Null'),
[TypeDefInfo.Null]: (registry: Registry, _: TypeDef): Constructor => createClass(registry, 'Null'),
[TypeDefInfo.Option]: (registry: Registry, value: TypeDef): Constructor => Option.with(getSubType(value)),
@@ -150,7 +154,7 @@ const infoMapping: Record<TypeDefInfo, (registry: Registry, value: TypeDef) => C
return (
subType === 'u8'
? ClassOf(registry, 'Bytes')
? createClass(registry, 'Bytes')
: Vec.with(subType)
);
},
+5 -5
View File
@@ -4,7 +4,7 @@
import Int from '../codec/Int';
import CodecSet from '../codec/Set';
import { createClass, createTypeUnsafe, ClassOf, TypeRegistry } from '.';
import { createClass, createTypeUnsafe, TypeRegistry } from '.';
describe('createType', (): void => {
const registry = new TypeRegistry();
@@ -111,12 +111,12 @@ describe('createType', (): void => {
it('instanceof should work (primitive type)', (): void => {
const value = registry.createType('Balance', 1234);
expect(value instanceof ClassOf(registry, 'Balance')).toBe(true);
expect(value instanceof registry.createClass('Balance')).toBe(true);
});
it('instanceof should work (srml type)', (): void => {
const value = registry.createType('Gas', 1234);
const Gas = ClassOf(registry, 'Gas');
const Gas = registry.createClass('Gas');
expect(value instanceof Gas).toBe(true);
});
@@ -144,14 +144,14 @@ describe('createType', (): void => {
it('allows for re-registration of a type', (): void => {
const balDef = registry.createType('Balance');
expect(balDef instanceof ClassOf(registry, 'Balance'));
expect(balDef instanceof registry.createClass('Balance'));
expect(balDef.bitLength()).toEqual(128);
registry.register({ Balance: 'u32' });
const balu32 = registry.createType('Balance');
expect(balu32 instanceof ClassOf(registry, 'Balance'));
expect(balu32 instanceof registry.createClass('Balance'));
expect(balu32.bitLength()).toEqual(32);
});
+1
View File
@@ -135,6 +135,7 @@ const nestedExtraction: [string, string, TypeDefInfo, (value: TypeDef, type: str
['(', ')', TypeDefInfo.Tuple, _decodeTuple],
// the inner for these are the same as tuple, multiple values
['BTreeMap<', '>', TypeDefInfo.BTreeMap, _decodeTuple],
['HashMap<', '>', TypeDefInfo.HashMap, _decodeTuple],
['Int<', '>', TypeDefInfo.Int, _decodeInt],
['Result<', '>', TypeDefInfo.Result, _decodeTuple],
['UInt<', '>', TypeDefInfo.UInt, _decodeUInt]
+7
View File
@@ -128,6 +128,13 @@ export class TypeRegistry implements Registry {
: formatBalance.getDefaults().unit;
}
/**
* @describe Creates an instance of the class
*/
public createClass <K extends keyof InterfaceTypes> (type: K): Constructor<InterfaceTypes[K]> {
return createClass(this, type) as any;
}
/**
* @description Creates an instance of a type as registered
*/
+1 -1
View File
@@ -5,7 +5,7 @@
type Mapper = (value: string) => string;
const ALLOWED_BOXES = ['BTreeMap', 'BTreeSet', 'Compact', 'Int', 'Linkage', 'Result', 'Option', 'UInt', 'Vec'];
const ALLOWED_BOXES = ['BTreeMap', 'BTreeSet', 'Compact', 'HashMap', 'Int', 'Linkage', 'Result', 'Option', 'UInt', 'Vec'];
const BOX_PRECEDING = ['<', '(', '[', '"', ',', ' ']; // start of vec, tuple, fixed array, part of struct def or in tuple
const mappings: Mapper[] = [
+1
View File
@@ -23,6 +23,7 @@ export enum TypeDefInfo {
Tuple,
Vec,
VecFixed,
HashMap,
Int,
UInt,
// anything not fully supported (keep this as the last entry)
+1 -2
View File
@@ -9,7 +9,6 @@ import { AnyJson, AnyU8a, ArgsDef, Codec, ExtrinsicPayloadValue, IExtrinsic, IKe
import { assert, isHex, isU8a, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { ClassOf } from '../create';
import Base from '../codec/Base';
import Compact from '../codec/Compact';
import { ExtrinsicValueV1 } from './v1/Extrinsic';
@@ -74,7 +73,7 @@ export default class Extrinsic extends Base<ExtrinsicVx | ExtrinsicUnknown> impl
public static decodeExtrinsic (registry: Registry, value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, version: number = DEFAULT_VERSION): ExtrinsicVx | ExtrinsicUnknown {
if (isU8a(value) || Array.isArray(value) || isHex(value)) {
return Extrinsic.decodeU8a(registry, u8aToU8a(value), version);
} else if (value instanceof ClassOf(registry, 'Call')) {
} else if (value instanceof registry.createClass('Call')) {
return Extrinsic.newFromValue(registry, { method: value }, version);
}
+1 -2
View File
@@ -9,7 +9,6 @@ import { ExtrinsicOptions } from '../types';
import { isU8a } from '@polkadot/util';
import { ClassOf } from '../../create';
import Struct from '../../codec/Struct';
const TRANSACTION_VERSION = 2;
@@ -36,7 +35,7 @@ export default class ExtrinsicV2 extends Struct implements IExtrinsicImpl {
public static decodeExtrinsic (registry: Registry, value?: Call | Uint8Array | ExtrinsicValueV2, isSigned = false): ExtrinsicValueV2 {
if (value instanceof ExtrinsicV2) {
return value;
} else if (value instanceof ClassOf(registry, 'Call')) {
} else if (value instanceof registry.createClass('Call')) {
return { method: value };
} else if (isU8a(value)) {
// here we decode manually since we need to pull through the version information
+1 -2
View File
@@ -9,7 +9,6 @@ import { ExtrinsicOptions } from '../types';
import { isU8a } from '@polkadot/util';
import { ClassOf } from '../../create';
import Struct from '../../codec/Struct';
const TRANSACTION_VERSION = 3;
@@ -36,7 +35,7 @@ export default class ExtrinsicV3 extends Struct implements IExtrinsicImpl {
public static decodeExtrinsic (registry: Registry, value?: Call | Uint8Array | ExtrinsicValueV3, isSigned = false): ExtrinsicValueV3 {
if (value instanceof ExtrinsicV3) {
return value;
} else if (value instanceof ClassOf(registry, 'Call')) {
} else if (value instanceof registry.createClass('Call')) {
return { method: value };
} else if (isU8a(value)) {
// here we decode manually since we need to pull through the version information
+1 -2
View File
@@ -9,7 +9,6 @@ import { ExtrinsicOptions } from '../types';
import { isU8a } from '@polkadot/util';
import { ClassOf } from '../../create';
import Struct from '../../codec/Struct';
export const TRANSACTION_VERSION = 4;
@@ -36,7 +35,7 @@ export default class ExtrinsicV4 extends Struct implements IExtrinsicImpl {
public static decodeExtrinsic (registry: Registry, value?: Call | Uint8Array | ExtrinsicValueV4, isSigned = false): ExtrinsicValueV4 {
if (value instanceof ExtrinsicV4) {
return value;
} else if (value instanceof ClassOf(registry, 'Call')) {
} else if (value instanceof registry.createClass('Call')) {
return { method: value };
} else if (isU8a(value)) {
// here we decode manually since we need to pull through the version information
@@ -41,9 +41,8 @@ export default {
peerId: 'Text',
listenedAddresses: 'Vec<Text>',
externalAddresses: 'Vec<Text>',
// FIXME These are HashMap
connectedPeers: 'BTreeMap<Text, Peer>',
notConnectedPeers: 'BTreeMap<Text, NotConnectedPeer>',
connectedPeers: 'HashMap<Text, Peer>',
notConnectedPeers: 'HashMap<Text, NotConnectedPeer>',
averageDownloadPerSec: 'u64',
averageUploadPerSec: 'u64',
peerset: 'NetworkStatePeerset'
@@ -78,8 +77,7 @@ export default {
},
NetworkStatePeerset: {
messageQueue: 'u64',
// FIXME This is HashMap
nodes: 'BTreeMap<Text, NetworkStatePeersetInfo>'
nodes: 'HashMap<Text, NetworkStatePeersetInfo>'
},
NetworkStatePeersetInfo: {
connected: 'bool',
+4 -4
View File
@@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/no-empty-interface */
import { ITuple } from '@polkadot/types/types';
import { BTreeMap, Enum, Option, Struct, U8aFixed, Vec } from '@polkadot/types/codec';
import { Enum, HashMap, Option, Struct, U8aFixed, Vec } from '@polkadot/types/codec';
import { Bytes, StorageKey, Text, bool, u32, u64, u8 } from '@polkadot/types/primitive';
import { Balance, BlockNumber, DispatchClass, Hash, StorageData, Weight } from '@polkadot/types/interfaces/runtime';
@@ -62,8 +62,8 @@ export interface NetworkState extends Struct {
readonly peerId: Text;
readonly listenedAddresses: Vec<Text>;
readonly externalAddresses: Vec<Text>;
readonly connectedPeers: BTreeMap<Text, Peer>;
readonly notConnectedPeers: BTreeMap<Text, NotConnectedPeer>;
readonly connectedPeers: HashMap<Text, Peer>;
readonly notConnectedPeers: HashMap<Text, NotConnectedPeer>;
readonly averageDownloadPerSec: u64;
readonly averageUploadPerSec: u64;
readonly peerset: NetworkStatePeerset;
@@ -72,7 +72,7 @@ export interface NetworkState extends Struct {
/** @name NetworkStatePeerset */
export interface NetworkStatePeerset extends Struct {
readonly messageQueue: u64;
readonly nodes: BTreeMap<Text, NetworkStatePeersetInfo>;
readonly nodes: HashMap<Text, NetworkStatePeersetInfo>;
}
/** @name NetworkStatePeersetInfo */
+1
View File
@@ -92,6 +92,7 @@ export interface Registry {
// keep this as a generic Codec, however the actual impl. returns the correct
findMetaEvent (eventIndex: Uint8Array): Constructor<any>;
createClass <K extends keyof InterfaceTypes> (type: K): Constructor<InterfaceTypes[K]>;
createType <K extends keyof InterfaceTypes> (type: K, ...params: any[]): InterfaceTypes[K];
get <T extends Codec = Codec> (name: string, withUnknown?: boolean): Constructor<T> | undefined;
getChainProperties (): ChainProperties | undefined;