From 63229133105da1394b6e153a7728257517be9eb3 Mon Sep 17 00:00:00 2001 From: Jaco Date: Thu, 1 Jul 2021 13:54:02 +0300 Subject: [PATCH] Allow for fallback types (struct-only as a start) (#3714) * Allow for fallback types (struct-only as a start) * Filter fallback & alias from structs * Don't clobber existing fallbackType --- CHANGELOG.md | 1 + packages/types/src/create/createClass.ts | 13 ++++++++++-- packages/types/src/create/createType.ts | 21 +++++++++++++++++-- packages/types/src/create/getTypeDef.ts | 4 +++- packages/types/src/create/types.ts | 3 ++- .../src/interfaces/system/definitions.ts | 8 +++++++ packages/types/src/types/codec.ts | 5 +++++ packages/types/src/types/definitions.ts | 7 ++++++- 8 files changed, 55 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d770695703..29802c32d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Contributed: Changes: +- Added `fallbackType` for type classes (only struct, as defined) - Allow `instances` API config to drive collective locations diff --git a/packages/types/src/create/createClass.ts b/packages/types/src/create/createClass.ts index 162a4dcd13..5a8801b638 100644 --- a/packages/types/src/create/createClass.ts +++ b/packages/types/src/create/createClass.ts @@ -175,7 +175,7 @@ const infoMapping: Record C // Returns the type Class for construction export function getTypeClass (registry: Registry, value: TypeDef): Constructor { - const Type = registry.get(value.type); + let Type = registry.get(value.type); if (Type) { return Type; @@ -185,5 +185,14 @@ export function getTypeClass (registry: Registry, value assert(getFn, () => `Unable to construct class from ${stringify(value)}`); - return getFn(registry, value) as Constructor; + Type = getFn(registry, value) as Constructor; + + // don't clobber any existing + if (!Type.__fallbackType && value.fallbackType) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ...this is the only place we we actually assign this... + Type.__fallbackType = value.fallbackType; + } + + return Type; } diff --git a/packages/types/src/create/createType.ts b/packages/types/src/create/createType.ts index 56f4a7310d..6e655c3eae 100644 --- a/packages/types/src/create/createType.ts +++ b/packages/types/src/create/createType.ts @@ -55,11 +55,28 @@ function initType (registry: // argument here can be any string, which, when it cannot parse, will yield a // runtime error. export function createTypeUnsafe (registry: Registry, type: K, params: unknown[] = [], options: CreateOptions = {}): T { + let Clazz: Constructor> | null = null; + let firstError: Error | null = null; + try { - return initType(registry, createClass(registry, type), params, options); + Clazz = createClass(registry, type); + + return initType(registry, Clazz, params, options); } catch (error) { - throw new Error(`createType(${type}):: ${(error as Error).message}`); + firstError = new Error(`createType(${type}):: ${(error as Error).message}`); } + + if (Clazz && Clazz.__fallbackType) { + try { + Clazz = createClass(registry, Clazz.__fallbackType as unknown as K); + + return initType(registry, Clazz, params, options); + } catch { + // swallow, we will throw the first error again + } + } + + throw firstError; } /** diff --git a/packages/types/src/create/getTypeDef.ts b/packages/types/src/create/getTypeDef.ts index 3574674475..2b75bdb505 100644 --- a/packages/types/src/create/getTypeDef.ts +++ b/packages/types/src/create/getTypeDef.ts @@ -15,6 +15,7 @@ interface TypeDefOptions { } const MAX_NESTED = 64; +const KNOWN_INTERNALS = ['_alias', '_fallback']; function getTypeString (typeOrObj: any): string { return isString(typeOrObj) @@ -100,7 +101,8 @@ function _decodeStruct (value: TypeDef, type: string, _: string, count: number): value.alias = parsed._alias ? new Map(Object.entries(parsed._alias)) : undefined; - value.sub = keys.filter((name) => !['_alias'].includes(name)).map((name): TypeDef => + value.fallbackType = parsed._fallback as string | undefined; + value.sub = keys.filter((name) => !KNOWN_INTERNALS.includes(name)).map((name): TypeDef => getTypeDef(getTypeString(parsed[name]), { name }, count) ); diff --git a/packages/types/src/create/types.ts b/packages/types/src/create/types.ts index 014032be1b..573be38610 100644 --- a/packages/types/src/create/types.ts +++ b/packages/types/src/create/types.ts @@ -32,9 +32,10 @@ export enum TypeDefInfo { export interface TypeDef { alias?: Map; + displayName?: string; + fallbackType?: string; info: TypeDefInfo; index?: number; - displayName?: string; length?: number; name?: string; namespace?: string; diff --git a/packages/types/src/interfaces/system/definitions.ts b/packages/types/src/interfaces/system/definitions.ts index 4e9a61ad71..ebffabbe99 100644 --- a/packages/types/src/interfaces/system/definitions.ts +++ b/packages/types/src/interfaces/system/definitions.ts @@ -140,12 +140,19 @@ export default { }, types: { AccountInfo: 'AccountInfoWithTripleRefCount', + AccountInfoWithRefCountU8: { + nonce: 'Index', + refcount: 'u8', + data: 'AccountData' + }, AccountInfoWithRefCount: { + _fallback: 'AccountInfoWithRefCountU8', nonce: 'Index', refcount: 'RefCount', data: 'AccountData' }, AccountInfoWithDualRefCount: { + _fallback: 'AccountInfoWithRefCount', nonce: 'Index', consumers: 'RefCount', providers: 'RefCount', @@ -154,6 +161,7 @@ export default { // original naming AccountInfoWithProviders: 'AccountInfoWithDualRefCount', AccountInfoWithTripleRefCount: { + _fallback: 'AccountInfoWithDualRefCount', nonce: 'Index', consumers: 'RefCount', providers: 'RefCount', diff --git a/packages/types/src/types/codec.ts b/packages/types/src/types/codec.ts index 65fabe3d78..a941e6233f 100644 --- a/packages/types/src/types/codec.ts +++ b/packages/types/src/types/codec.ts @@ -108,6 +108,11 @@ export type CodecArg = Codec | BigInt | BN | boolean | string | Uint8Array | boo interface CodecArgArray extends Array {} export interface Constructor { + /** + * @description An internal fallback type (previous generation) if encoding fails + */ + readonly __fallbackType?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any new(registry: Registry, ...value: any[]): T; } diff --git a/packages/types/src/types/definitions.ts b/packages/types/src/types/definitions.ts index 72efa7cb13..3398b13af9 100644 --- a/packages/types/src/types/definitions.ts +++ b/packages/types/src/types/definitions.ts @@ -7,7 +7,12 @@ export type DefinitionTypeEnum = { _enum: DefinitionTypeType[] } | { _enum: Reco export type DefinitionTypeSet = { _set: Record }; -export type DefinitionTypeStruct = Record | { _alias?: Record } & Record; +type DefinitionTypeStructExtra = { + _alias?: Record; + _fallback?: DefinitionTypeType; +} & Record; + +export type DefinitionTypeStruct = Record | DefinitionTypeStructExtra; export type DefinitionType = string | DefinitionTypeEnum | DefinitionTypeSet | DefinitionTypeStruct;