diff --git a/CHANGELOG.md b/CHANGELOG.md index 87d7e4ee7d..aef43d8976 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # CHANGELOG +## master + +Changes: + +- Adjust RPC to use registry.createType with optionality (required for metadata v14) +- Adjust sorting for TS type generation + + ## 5.1.1 Jul 19, 2021 - **Breaking changes** With the support for v14 metadata parsing, the `documentation` fields on metadata was renamed to `docs` for consistency, aligning with the SCALE type generators. diff --git a/packages/rpc-core/src/bundle.ts b/packages/rpc-core/src/bundle.ts index 1d7354394d..e8093da763 100644 --- a/packages/rpc-core/src/bundle.ts +++ b/packages/rpc-core/src/bundle.ts @@ -11,7 +11,7 @@ import type { RpcInterface, RpcInterfaceMethod } from './types'; import { Observable, publishReplay, refCount } from 'rxjs'; -import { createClass, createTypeUnsafe, Option, rpcDefinitions } from '@polkadot/types'; +import { rpcDefinitions } from '@polkadot/types'; import { assert, hexToU8a, isFunction, isNull, isUndefined, logger, memoize, u8aToU8a } from '@polkadot/util'; import { drr, refCountDelay } from './util'; @@ -339,7 +339,7 @@ export class RpcCore { 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], { blockHash }) + registry.createTypeUnsafe(def.params[index].type, [input], { blockHash }) ); } @@ -366,7 +366,7 @@ export class RpcCore { : mapped as unknown as Codec[]; } - return createTypeUnsafe(registry, rpc.type, [result], { blockHash }); + return registry.createTypeUnsafe(rpc.type, [result], { blockHash }); } private _formatStorageData (registry: Registry, blockHash: Uint8Array | string | null | undefined, key: StorageKey, value: string | null): Codec { @@ -432,29 +432,15 @@ export class RpcCore { : ` entry ${entryIndex}:`; try { - if (meta.modifier.isOptional) { - let inner = null; - - if (!isEmpty) { - inner = createTypeUnsafe(registry, type, [input], { blockHash, isPedantic: true }); - } - - const option = new Option(registry, createClass(registry, type), inner); - - if (blockHash) { - option.createdAtHash = registry.createType('Hash', blockHash); - } - - return option; - } - - return createTypeUnsafe(registry, type, [ + return registry.createTypeUnsafe(type, [ isEmpty ? meta.fallback ? hexToU8a(meta.fallback.toHex()) : undefined - : input - ], { blockHash, isPedantic: true }); + : meta.modifier.isOptional + ? registry.createTypeUnsafe(type, [input], { blockHash, isPedantic: true }) + : input + ], { blockHash, isOptional: meta.modifier.isOptional, isPedantic: !meta.modifier.isOptional }); } catch (error) { throw new Error(`Unable to decode storage ${key.section || 'unknown'}.${key.method || 'unknown'}:${entryNum}: ${(error as Error).message}`); } diff --git a/packages/typegen/src/util/index.ts b/packages/typegen/src/util/index.ts index 3e13faac88..6028f1fcc9 100644 --- a/packages/typegen/src/util/index.ts +++ b/packages/typegen/src/util/index.ts @@ -9,5 +9,8 @@ export * from './imports'; export * from './initMeta'; export * from './register'; -export const compareName = (a: { name: { toString(): string } }, b: { name: { toString(): string } }): number => - a.name.toString().localeCompare(b.name.toString()); +type Cmp = { name: { toString(): string } }; + +export function compareName (a: Cmp, b: Cmp): number { + return a.name.toString().localeCompare(b.name.toString()); +} diff --git a/packages/types/src/create/createType.ts b/packages/types/src/create/createType.ts index 6e655c3eae..638ddf2fca 100644 --- a/packages/types/src/create/createType.ts +++ b/packages/types/src/create/createType.ts @@ -3,20 +3,16 @@ import type { Bytes } from '../primitive/Bytes'; import type { Codec, Constructor, InterfaceTypes, Registry } from '../types'; -import type { FromReg } from './types'; +import type { CreateOptions, FromReg } from './types'; import { assert, isHex, isU8a, u8aEq, u8aToHex, u8aToU8a } from '@polkadot/util'; +import { Option } from '../codec/Option'; import { createClass } from './createClass'; -interface CreateOptions { - blockHash?: Uint8Array | string | null; - isPedantic?: boolean; -} - // 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 (value: Uint8Array, created: FromReg): void { +function checkInstance (created: FromReg, value: Uint8Array): void { const u8a = created.toU8a(); const rawType = created.toRawType(); @@ -30,25 +26,29 @@ function checkInstance (valu ); } -// 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 (registry: Registry, Type: Constructor>, params: unknown[] = [], { blockHash, isPedantic }: CreateOptions = {}): FromReg { - const created = new Type(registry, ...params); - const value = params[0]; - +function checkPedantic (created: FromReg, [value]: unknown[], isPedantic = false): void { if (isPedantic) { if (isU8a(value)) { - checkInstance(value, created); + checkInstance(created, value); } else if (isHex(value)) { - checkInstance(u8aToU8a(value), created); + checkInstance(created, u8aToU8a(value)); } } +} + +// 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 (registry: Registry, Type: Constructor>, params: unknown[] = [], { blockHash, isOptional, isPedantic }: CreateOptions = {}): FromReg { + const created = new (isOptional ? Option.with(Type) : Type)(registry, ...params); + + checkPedantic(created, params, isPedantic); if (blockHash) { created.createdAtHash = createType(registry, 'Hash', blockHash); } - return created; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return created as any; } // An unsafe version of the `createType` below. It's unsafe because the `type` diff --git a/packages/types/src/create/registry.ts b/packages/types/src/create/registry.ts index 681e9f7d09..4b835c1282 100644 --- a/packages/types/src/create/registry.ts +++ b/packages/types/src/create/registry.ts @@ -6,6 +6,7 @@ import type { ExtDef } from '../extrinsic/signedExtensions/types'; import type { ChainProperties, CodecHash, DispatchErrorModule, Hash, MetadataLatest, PortableRegistry, SiLookupTypeId } from '../interfaces/types'; import type { CallFunction, Codec, CodecHasher, Constructor, InterfaceTypes, RegisteredTypes, Registry, RegistryError, RegistryTypes } from '../types'; +import type { CreateOptions } from './types'; import { assert, assertReturn, BN_ZERO, formatBalance, isFunction, isString, isU8a, logger, stringCamelCase, stringify, u8aToHex } from '@polkadot/util'; import { blake2AsU8a } from '@polkadot/util-crypto'; @@ -20,7 +21,7 @@ import * as definitions from '../interfaces/definitions'; import { decorateConstants, decorateExtrinsics } from '../metadata/decorate'; import { Metadata } from '../metadata/Metadata'; import { createClass, getTypeClass } from './createClass'; -import { createType } from './createType'; +import { createTypeUnsafe } from './createType'; import { getTypeDef } from './getTypeDef'; const l = logger('registry'); @@ -247,7 +248,14 @@ export class TypeRegistry implements Registry { * @description Creates an instance of a type as registered */ public createType (type: K, ...params: unknown[]): InterfaceTypes[K] { - return createType(this, type, ...params); + return createTypeUnsafe(this, type, params); + } + + /** + * @description Creates an instance of a type as registered + */ + public createTypeUnsafe (type: K, params: unknown[], options?: CreateOptions): T { + return createTypeUnsafe(this, type, params, options); } // find a specific call diff --git a/packages/types/src/create/types.ts b/packages/types/src/create/types.ts index 595547d453..cef1359844 100644 --- a/packages/types/src/create/types.ts +++ b/packages/types/src/create/types.ts @@ -43,3 +43,9 @@ export interface TypeDef { sub?: TypeDef | TypeDef[]; type: string; } + +export interface CreateOptions { + blockHash?: Uint8Array | string | null; + isOptional?: boolean; + isPedantic?: boolean; +} diff --git a/packages/types/src/types/registry.ts b/packages/types/src/types/registry.ts index 220ea25687..d531b090cf 100644 --- a/packages/types/src/types/registry.ts +++ b/packages/types/src/types/registry.ts @@ -3,6 +3,7 @@ import type { Observable } from 'rxjs'; import type { BN } from '@polkadot/util'; +import type { CreateOptions } from '../create/types'; import type { ExtDef } from '../extrinsic/signedExtensions/types'; import type { MetadataLatest, PortableRegistry } from '../interfaces/metadata'; import type { CodecHash, Hash } from '../interfaces/runtime'; @@ -120,6 +121,7 @@ export interface Registry { createClass (type: K): Constructor; createType (type: K, ...params: unknown[]): InterfaceTypes[K]; + createTypeUnsafe (type: K, params: unknown[], options?: CreateOptions): T; get (name: string, withUnknown?: boolean): Constructor | undefined; getChainProperties (): ChainProperties | undefined; getClassName (clazz: Constructor): string | undefined;