Add createdAtHash to Codec interface (#3276)

* Add createdAtHash to Codec interface

* Adjust linkedHash (also on )

* createdAtHash
This commit is contained in:
Jaco Greeff
2021-03-07 16:00:30 +01:00
committed by GitHub
parent 22e5488f16
commit 3c9b7de6c7
26 changed files with 154 additions and 96 deletions
@@ -2,8 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
import type { ApiInterfaceRx } from '@polkadot/api/types';
import type { AccountId, EventRecord, SignedBlock } from '@polkadot/types/interfaces';
import type { Vec } from '@polkadot/types';
import type { EventRecord, SignedBlock } from '@polkadot/types/interfaces';
import type { Observable } from '@polkadot/x-rxjs';
import type { HeaderExtended } from '../type';
import { combineLatest, of } from '@polkadot/x-rxjs';
import { map, switchMap } from '@polkadot/x-rxjs/operators';
@@ -18,17 +20,17 @@ import { memo } from '../util';
export function subscribeNewBlocks (instanceId: string, api: ApiInterfaceRx): () => Observable<SignedBlockExtended> {
return memo(instanceId, (): Observable<SignedBlockExtended> =>
api.derive.chain.subscribeNewHeads().pipe(
switchMap((header): Observable<[SignedBlock, EventRecord[], AccountId[] | undefined]> => {
const blockHash = header.hash;
switchMap((header): Observable<[SignedBlock, Vec<EventRecord>, HeaderExtended]> => {
const blockHash = header.createdAtHash || header.hash;
return combineLatest(
api.rpc.chain.getBlock(blockHash),
api.query.system.events.at(blockHash),
of(header.validators)
of(header)
);
}),
map(([block, events, validators]) =>
new SignedBlockExtended(api.registry, block, events, validators)
map(([block, events, header]) =>
new SignedBlockExtended(api.registry, block, events, header.validators)
)
)
);
@@ -29,10 +29,13 @@ export function subscribeNewHeads (instanceId: string, api: ApiInterfaceRx): ()
api.rpc.chain.subscribeNewHeads(),
api.query.session
? api.query.session.validators()
: of([])
: of(undefined)
]).pipe(
map(([header, validators]): HeaderExtended =>
new HeaderExtended(api.registry, header, validators)
)
));
map(([header, validators]): HeaderExtended => {
header.createdAtHash = header.hash;
return new HeaderExtended(api.registry, header, validators);
})
)
);
}
@@ -26,6 +26,7 @@ export class HeaderExtended extends _Header {
this.#author = extractAuthor(this.digest, validators);
this.#validators = validators;
this.createdAtHash = header?.createdAtHash;
}
/**
@@ -53,12 +53,13 @@ export class SignedBlockExtended extends _SignedBlock {
readonly #events: EventRecord[];
readonly #extrinsics: TxWithEvent[];
constructor (registry: Registry, block?: SignedBlock, events?: EventRecord[], sessionValidators?: AccountId[]) {
constructor (registry: Registry, block?: SignedBlock, events?: EventRecord[], validators?: AccountId[]) {
super(registry, block);
this.#author = extractAuthor(this.block.header.digest, sessionValidators);
this.#author = extractAuthor(this.block.header.digest, validators);
this.#events = events || ([] as EventRecord[]);
this.#extrinsics = mapExtrinsics(this.block.extrinsics, this.#events);
this.createdAtHash = block?.createdAtHash;
}
/**
+1 -1
View File
@@ -139,7 +139,7 @@ export abstract class Init<ApiType extends ApiTypes> extends Decorate<ApiType> {
// nothing has been found, construct new
const metadata = await this._rpcCore.state.getMetadata(header.parentHash).toPromise();
const registry = this._initRegistry(new TypeRegistry(), this._runtimeChain as Text, version, metadata);
const registry = this._initRegistry(new TypeRegistry(blockHash), this._runtimeChain as Text, version, metadata);
// For now, since this is new we ignore the capability lookups (this could be useful once proven)
// this._detectCapabilities(registry, blockHash);
+33 -27
View File
@@ -244,17 +244,17 @@ export class RpcCore implements RpcInterface {
// execute the RPC call, doing a registry swap for historic as applicable
const callWithRegistry = async (outputAs: OutputType, values: any[]): Promise<Codec | Codec[]> => {
const hash = hashIndex === -1
? undefined
const blockHash = hashIndex === -1
? null
: values[hashIndex] as Uint8Array;
const { registry } = hash && this.#getBlockRegistry
? await this.#getBlockRegistry(hash)
const { registry } = blockHash && this.#getBlockRegistry
? await this.#getBlockRegistry(blockHash)
: { registry: this.#registryDefault };
const params = this._formatInputs(registry, def, values);
const params = this._formatInputs(registry, null, def, values);
const data = await this.provider.send(rpcName, params.map((param): AnyJson => param.toJSON())) as AnyJson;
return outputAs === 'scale'
? this._formatOutput(registry, method, def, params, data)
? this._formatOutput(registry, blockHash, method, def, params, data)
: registry.createType(outputAs === 'raw' ? 'Raw' : 'Json', data);
};
@@ -324,7 +324,7 @@ export class RpcCore implements RpcInterface {
};
try {
const params = this._formatInputs(registry, def, values);
const params = this._formatInputs(registry, null, def, values);
const paramsJson = params.map((param): AnyJson => param.toJSON());
const update = (error?: Error | null, result?: any): void => {
@@ -337,7 +337,7 @@ export class RpcCore implements RpcInterface {
try {
observer.next(
outputAs === 'scale'
? this._formatOutput(registry, method, def, params, result)
? this._formatOutput(registry, null, method, def, params, result)
: registry.createType(outputAs === 'raw' ? 'Raw' : 'Json', result)
);
} catch (error) {
@@ -372,8 +372,8 @@ export class RpcCore implements RpcInterface {
return memoized;
}
private _formatInputs (registry: Registry, def: DefinitionRpc, inputs: any[]): Codec[] {
const reqArgCount = def.params.filter(({ isOptional }): boolean => !isOptional).length;
private _formatInputs (registry: Registry, blockHash: Uint8Array | string | null | undefined, def: DefinitionRpc, inputs: any[]): Codec[] {
const reqArgCount = def.params.filter(({ isOptional }) => !isOptional).length;
const optText = reqArgCount === def.params.length
? ''
: ` (${def.params.length - reqArgCount} optional)`;
@@ -381,25 +381,25 @@ export class RpcCore implements RpcInterface {
assert(inputs.length >= reqArgCount && inputs.length <= def.params.length, `Expected ${def.params.length} parameters${optText}, ${inputs.length} found instead`);
return inputs.map((input, index): Codec =>
createTypeUnsafe(registry, def.params[index].type, [input])
createTypeUnsafe(registry, def.params[index].type, [input], { blockHash })
);
}
private _formatOutput (registry: Registry, method: string, rpc: DefinitionRpc, params: Codec[], result?: any): Codec | Codec[] {
private _formatOutput (registry: Registry, blockHash: Uint8Array | string | null | undefined, method: string, rpc: DefinitionRpc, params: Codec[], result?: any): Codec | Codec[] {
if (rpc.type === 'StorageData') {
const key = params[0] as StorageKey;
return this._formatStorageData(registry, key, result);
return this._formatStorageData(registry, blockHash, key, result);
} else if (rpc.type === 'StorageChangeSet') {
const keys = params[0] as Vec<StorageKey>;
return keys
? this._formatStorageSet(registry, keys, (result as StorageChangeSetJSON).changes)
? this._formatStorageSet(registry, (result as StorageChangeSetJSON).block, keys, (result as StorageChangeSetJSON).changes)
: registry.createType('StorageChangeSet', result);
} else if (rpc.type === 'Vec<StorageChangeSet>') {
const mapped = (result as StorageChangeSetJSON[]).map(({ block, changes }): [Hash, Codec[]] => [
registry.createType('Hash', block),
this._formatStorageSet(registry, params[0] as Vec<StorageKey>, changes)
this._formatStorageSet(registry, block, params[0] as Vec<StorageKey>, changes)
]);
// we only query at a specific block, not a range - flatten
@@ -408,10 +408,10 @@ export class RpcCore implements RpcInterface {
: mapped as unknown as Codec[];
}
return createTypeUnsafe(registry, rpc.type, [result]);
return createTypeUnsafe(registry, rpc.type, [result], { blockHash });
}
private _formatStorageData (registry: Registry, key: StorageKey, value: string | null): Codec {
private _formatStorageData (registry: Registry, blockHash: Uint8Array | string | null | undefined, key: StorageKey, value: string | null): Codec {
const isEmpty = isNull(value);
// we convert to Uint8Array since it maps to the raw encoding, all
@@ -422,10 +422,10 @@ export class RpcCore implements RpcInterface {
? value
: u8aToU8a(value);
return this._newType(registry, key, input, isEmpty);
return this._newType(registry, blockHash, key, input, isEmpty);
}
private _formatStorageSet (registry: Registry, keys: Vec<StorageKey>, changes: [string, string | null][]): Codec[] {
private _formatStorageSet (registry: Registry, blockHash: string, keys: Vec<StorageKey>, changes: [string, string | null][]): Codec[] {
// For StorageChangeSet, the changes has the [key, value] mappings
const withCache = keys.length !== 1;
@@ -434,13 +434,13 @@ export class RpcCore implements RpcInterface {
// - Codec - There is a valid value, non-empty
// - null - The storage key is empty
return keys.reduce((results: Codec[], key: StorageKey, index): Codec[] => {
results.push(this._formatStorageSetEntry(registry, key, changes, withCache, index));
results.push(this._formatStorageSetEntry(registry, blockHash, key, changes, withCache, index));
return results;
}, []);
}
private _formatStorageSetEntry (registry: Registry, key: StorageKey, changes: [string, string | null][], witCache: boolean, entryIndex: number): Codec {
private _formatStorageSetEntry (registry: Registry, blockHash: string, key: StorageKey, changes: [string, string | null][], witCache: boolean, entryIndex: number): Codec {
const hexKey = key.toHex();
const found = changes.find(([key]) => key === hexKey);
@@ -461,10 +461,10 @@ export class RpcCore implements RpcInterface {
// will increase memory beyond what is allowed.
this.#storageCache.set(hexKey, value);
return this._newType(registry, key, input, isEmpty, entryIndex);
return this._newType(registry, blockHash, key, input, isEmpty, entryIndex);
}
private _newType (registry: Registry, key: StorageKey, input: string | Uint8Array | null, isEmpty: boolean, entryIndex = -1): Codec {
private _newType (registry: Registry, blockHash: Uint8Array | string | null | undefined, key: StorageKey, input: string | Uint8Array | null, isEmpty: boolean, entryIndex = -1): Codec {
// single return value (via state.getStorage), decode the value based on the
// outputType that we have specified. Fallback to Raw on nothing
const type = key.outputType || 'Raw';
@@ -478,13 +478,19 @@ export class RpcCore implements RpcInterface {
if (!isEmpty) {
try {
inner = createTypeUnsafe(registry, type, [input], { isPedantic: true });
inner = createTypeUnsafe(registry, type, [input], { blockHash, isPedantic: true });
} catch (error) {
l.error(`Unable to decode storage ${key.section || 'unknown'}.${key.method || 'unknown'}:${entryNum}`, (error as Error).message);
}
}
return new Option(registry, createClass(registry, type), inner);
const option = new Option(registry, createClass(registry, type), inner);
if (blockHash) {
option.createdAtHash = registry.createType('Hash', blockHash);
}
return option;
}
try {
@@ -494,11 +500,11 @@ export class RpcCore implements RpcInterface {
? hexToU8a(meta.fallback.toHex())
: undefined
: input
], { isPedantic: true });
], { blockHash, isPedantic: true });
} catch (error) {
l.error(`Unable to decode storage ${key.section || 'unknown'}.${key.method || 'unknown'}:${entryNum}`, (error as Error).message);
return registry.createType('Raw', input);
return createTypeUnsafe(registry, 'Raw', [input], { blockHash });
}
}
}
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyJson, Codec, Registry } from '../types';
import { compactToU8a, u8aConcat, u8aToHex } from '@polkadot/util';
@@ -18,6 +18,8 @@ import { compareArray } from './utils';
export abstract class AbstractArray<T extends Codec> extends Array<T> implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
protected constructor (registry: Registry, ...values: T[]) {
super(...values);
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyNumber, Codec, Registry } from '../types';
import type { UIntBitLength } from './types';
@@ -67,6 +67,8 @@ function decodeAbstractInt (value: AnyNumber, bitLength: UIntBitLength, isNegati
export abstract class AbstractInt extends BN implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
readonly #bitLength: UIntBitLength;
readonly #isSigned: boolean;
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
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';
@@ -79,6 +79,8 @@ function decodeSet<V extends Codec = Codec> (registry: Registry, valType: Constr
export class BTreeSet<V extends Codec = Codec> extends Set<V> implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
readonly #ValClass: Constructor<V>;
constructor (registry: Registry, valType: Constructor<V> | keyof InterfaceTypes, rawValue?: Uint8Array | string | string[] | Set<any>) {
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyJson, BareOpts, Codec, Registry } from '../types';
/**
@@ -11,6 +11,8 @@ import type { AnyJson, BareOpts, Codec, Registry } from '../types';
export abstract class Base<T extends Codec> implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
protected readonly _raw: T;
protected constructor (registry: Registry, value: T) {
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces';
import type { CodecHash, Hash } from '../interfaces';
import type { AnyJson, AnyNumber, Constructor, ICompact, InterfaceTypes, Registry } from '../types';
import type { CompactEncodable, UIntBitLength } from './types';
@@ -22,6 +22,8 @@ import { typeToConstructor } from './utils';
export class Compact<T extends CompactEncodable> implements ICompact<T> {
public readonly registry: Registry;
public createdAtHash?: Hash;
readonly #Type: Constructor<T>;
readonly #raw: T;
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyNumber, Codec, Registry } from '../types';
import type { UIntBitLength } from './types';
@@ -24,6 +24,8 @@ const BITLENGTH: UIntBitLength = 64;
export class CodecDate extends Date implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
constructor (registry: Registry, value: CodecDate | Date | AnyNumber = 0) {
super(CodecDate.decodeDate(value));
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces';
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';
@@ -166,6 +166,8 @@ function decodeEnum (registry: Registry, def: TypesDef, value?: any, index?: num
export class Enum implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
readonly #def: TypesDef;
readonly #entryIndex: number;
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyJson, Codec, Registry } from '../types';
import { isFunction, isUndefined } from '@polkadot/util';
@@ -24,6 +24,8 @@ function decodeJson (value?: Record<string, unknown> | null): [string, any][] {
export class Json extends Map<string, any> implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
constructor (registry: Registry, value?: Record<string, unknown> | null) {
const decoded = decodeJson(value);
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
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';
@@ -88,6 +88,8 @@ function decodeMap<K extends Codec = Codec, V extends Codec = Codec> (registry:
export class CodecMap<K extends Codec = Codec, V extends Codec = Codec> extends Map<K, V> implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
readonly #KeyClass: Constructor<K>;
readonly #ValClass: Constructor<V>;
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces';
import type { CodecHash, Hash } from '../interfaces';
import type { AnyJson, Codec, Constructor, InterfaceTypes, Registry } from '../types';
import { assert, isNull, isU8a, isUndefined, u8aToHex } from '@polkadot/util';
@@ -50,6 +50,8 @@ function decodeOption (registry: Registry, typeName: Constructor | keyof Interfa
export class Option<T extends Codec> implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
readonly #Type: Constructor<T>;
readonly #raw: T;
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyJson, AnyU8a, IU8a, Registry } from '../types';
import { assert, isAscii, isUndefined, isUtf8, u8aToHex, u8aToString, u8aToU8a } from '@polkadot/util';
@@ -18,6 +18,8 @@ import { assert, isAscii, isUndefined, isUtf8, u8aToHex, u8aToString, u8aToU8a }
export class Raw extends Uint8Array implements IU8a {
public readonly registry: Registry;
public createdAtHash?: Hash;
constructor (registry: Registry, value?: AnyU8a) {
super(u8aToU8a(value));
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { Codec, Constructor, Registry } from '../types';
import BN from 'bn.js';
@@ -80,6 +80,8 @@ function decodeSet (setValues: SetValues, value: string[] | Set<string> | Uint8A
export class CodecSet extends Set<string> implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
readonly #allowed: SetValues;
readonly #byteLength: number;
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
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';
@@ -135,6 +135,8 @@ export class Struct<
E extends { [K in keyof S]: string } = { [K in keyof S]: string }> extends Map<keyof S, Codec> implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
readonly #jsonMap: Map<keyof S, string>;
readonly #Types: ConstructorDef;
+34 -34
View File
@@ -4,72 +4,72 @@
import type { Codec, Constructor, InterfaceTypes, Registry } from '../types';
import type { FromReg } from './types';
import { isU8a, logger, u8aToHex } from '@polkadot/util';
import { logger } from '@polkadot/util';
import { createClass } from './createClass';
interface UnsafeOptions {
interface CreateOptions {
blockHash?: Uint8Array | string | null;
isPedantic?: boolean;
withoutLog?: boolean;
}
const l = logger('registry');
function u8aHasValue (value: Uint8Array): boolean {
return value.some((v): boolean => !!v);
}
// TODO: Fix and re-enable
// With isPedantic, actually check that the encoding matches that supplied. This
// is much slower, but verifies that we have the correct types defined
function checkInstance<T extends Codec = Codec, K extends string = string> (value: Uint8Array, created: FromReg<T, K>): void {
// the underlying type created.toRawType()
const rawType = created.toRawType();
// function checkInstance<T extends Codec = Codec, K extends string = string> (value: Uint8Array, created: FromReg<T, K>): void {
// // the underlying type created.toRawType()
// const rawType = created.toRawType();
// ignore bytes completely - this is probably a FIXME, since these are somewhat
// breaking for at least online queries - not quite sure wtf is going wrong here
if (rawType === 'Bytes') {
return;
}
// // ignore bytes completely - this is probably a FIXME, since these are somewhat
// // breaking for at least online queries - not quite sure wtf is going wrong here
// if (rawType === 'Bytes') {
// return;
// }
// the hex values for what we have
const inHex = u8aToHex(value);
const crHex = created.toHex();
// // the hex values for what we have
// const inHex = u8aToHex(value);
// const crHex = created.toHex();
// Check equality, based on some different approaches (as decoded)
const isEqual = inHex === crHex || // raw hex values, quick path
inHex === created.toHex(true) || // wrapped options
u8aToHex(value.reverse()) === crHex; // reverse (for numbers, which are BE)
// // Check equality, based on some different approaches (as decoded)
// const isEqual = inHex === crHex || // raw hex values, quick path
// inHex === created.toHex(true) || // wrapped options
// u8aToHex(value.reverse()) === crHex; // reverse (for numbers, which are BE)
// if the hex doesn't match and the value for both is non-empty, complain... bitterly
if (!isEqual && (u8aHasValue(value) || u8aHasValue(created.toU8a(true)))) {
l.warn(`${rawType}:: Input doesn't match output, received ${u8aToHex(value)}, created ${crHex}`);
}
}
// // if the hex doesn't match and the value for both is non-empty, complain... bitterly
// if (!isEqual && (u8aHasValue(value) || u8aHasValue(created.toU8a(true)))) {
// l.warn(`${rawType}:: Input doesn't match output, received ${u8aToHex(value)}, created ${crHex}`);
// }
// }
// Initializes a type with a value. This also checks for fallbacks and in the cases
// where isPedantic is specified (storage decoding), also check the format/structure
function initType<T extends Codec = Codec, K extends string = string> (registry: Registry, Type: Constructor<FromReg<T, K>>, params: any[] = [], isPedantic?: boolean): FromReg<T, K> {
function initType<T extends Codec = Codec, K extends string = string> (registry: Registry, Type: Constructor<FromReg<T, K>>, params: any[] = [], { blockHash }: CreateOptions = {}): FromReg<T, K> {
const created = new Type(registry, ...params);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const [value] = params;
if (isPedantic && isU8a(value)) {
checkInstance(value, created);
if (blockHash) {
created.createdAtHash = createType(registry, 'Hash', blockHash);
}
// if (isPedantic && isU8a(value)) {
// checkInstance(value, created);
// }
return created;
}
// An unsafe version of the `createType` below. It's unsafe because the `type`
// argument here can be any string, which, when it cannot parse, will yield a
// runtime error.
export function createTypeUnsafe<T extends Codec = Codec, K extends string = string> (registry: Registry, type: K, params: any[] = [], { withoutLog }: UnsafeOptions = {}): T {
export function createTypeUnsafe<T extends Codec = Codec, K extends string = string> (registry: Registry, type: K, params: any[] = [], options: CreateOptions = {}): T {
try {
// Circle back to isPedantic when it handles all cases 100% - as of now,
// it provides false warning which is more hinderance than help
return initType(registry, createClass<T, K>(registry, type), params); // , isPedantic);
return initType(registry, createClass<T, K>(registry, type), params, options);
} catch (error) {
!withoutLog && l.error(error);
!options.withoutLog && l.error(error);
throw new Error(`createType(${type}):: ${(error as Error).message}`);
}
+8 -2
View File
@@ -4,7 +4,7 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import type { ExtDef } from '../extrinsic/signedExtensions/types';
import type { ChainProperties, CodecHash, DispatchErrorModule } from '../interfaces/types';
import type { ChainProperties, CodecHash, DispatchErrorModule, Hash } from '../interfaces/types';
import type { CallFunction, Codec, CodecHasher, Constructor, InterfaceTypes, RegisteredTypes, Registry, RegistryError, RegistryTypes } from '../types';
// we are attempting to avoid circular refs, hence the Metadata path import
@@ -136,11 +136,17 @@ export class TypeRegistry implements Registry {
#userExtensions?: ExtDef;
constructor () {
public createdAtHash?: Hash;
constructor (createdAtHash?: Hash | Uint8Array | string) {
this.#knownDefaults = { Json, Metadata, Raw, ...baseTypes };
this.#knownDefinitions = definitions as unknown as Record<string, { types: RegistryTypes }>;
this.init();
if (createdAtHash) {
this.createdAtHash = this.createType('Hash', createdAtHash);
}
}
public init (): this {
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { Codec, Registry } from '../types';
import { isU8a, u8aToHex } from '@polkadot/util';
@@ -26,6 +26,8 @@ function decodeBool (value: any): boolean {
export class bool extends Boolean implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
// eslint-disable-next-line @typescript-eslint/ban-types
constructor (registry: Registry, value: bool | Boolean | Uint8Array | boolean | number = false) {
super(decodeBool(value));
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { Codec, Registry } from '../types';
import { isNull } from '@polkadot/util';
@@ -14,6 +14,8 @@ import { isNull } from '@polkadot/util';
export class Null implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
constructor (registry: Registry) {
this.registry = registry;
}
+3 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/types authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { AnyU8a, Codec, Registry } from '../types';
import { assert, compactAddLength, compactFromU8a, hexToU8a, isHex, isString, stringToU8a, u8aToHex, u8aToString } from '@polkadot/util';
@@ -50,6 +50,8 @@ function decodeText (value?: null | Text | string | AnyU8a | { toString: () => s
export class Text extends String implements Codec {
public readonly registry: Registry;
public createdAtHash?: Hash;
#override: string | null = null;
constructor (registry: Registry, value?: null | Text | string | AnyU8a | { toString: () => string }) {
+7 -2
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type BN from 'bn.js';
import type { H256 } from '../interfaces/runtime';
import type { Hash } from '../interfaces/runtime';
import type { Registry } from './registry';
export type AnyJson = string | number | boolean | null | undefined | AnyJson[] | { [index: string]: AnyJson };
@@ -46,7 +46,7 @@ export interface Codec {
/**
* @description Returns a hash of the value
*/
readonly hash: H256;
readonly hash: Hash;
/**
* @description Checks if the value is an empty value
@@ -58,6 +58,11 @@ export interface Codec {
*/
readonly registry: Registry;
/**
* @description The block at which this value was retrieved/created (set to non-empty when retrieved from storage)
*/
createdAtHash?: Hash;
/**
* @description Compares the value of the input to see if there is a match
*/
+3 -1
View File
@@ -5,7 +5,7 @@ import type BN from 'bn.js';
import type { Metadata } from '@polkadot/metadata';
import type { Observable } from '@polkadot/x-rxjs';
import type { ExtDef } from '../extrinsic/signedExtensions/types';
import type { CodecHash } from '../interfaces/runtime';
import type { CodecHash, Hash } from '../interfaces/runtime';
import type { ChainProperties } from '../interfaces/system';
import type { CallFunction } from './calls';
import type { Codec, Constructor } from './codec';
@@ -101,6 +101,8 @@ export interface Registry {
readonly unknownTypes: string[];
readonly signedExtensions: string[];
createdAtHash?: Hash;
findMetaCall (callIndex: Uint8Array): CallFunction;
findMetaError (errorIndex: Uint8Array | { error: BN, index: BN }): RegistryError;
// due to same circular imports where types don't really want to import from EventData,