From 51d589e26b7d757472033addb22db1e0c38b8bdc Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 16 Aug 2019 11:25:38 +0200 Subject: [PATCH] Readability on Metadata & ExtrinsicSignature (#1314) * Readbility on Metadata & ExtrinsicSignature * Version payload * Adjust versioning * De-dup asVx --- .../src/consts/fromMetadata/index.ts | 2 +- .../src/extrinsics/fromMetadata/index.ts | 4 +- .../src/storage/fromMetadata/index.ts | 2 +- .../types/src/Metadata/MetadataVersioned.ts | 134 ++++++------------ packages/types/src/Metadata/util/testUtil.ts | 2 +- .../Extrinsic/v1/ExtrinsicSignature.ts | 8 +- .../Extrinsic/v2/ExtrinsicSignature.ts | 16 +-- .../Extrinsic/v3/ExtrinsicSignature.ts | 117 +-------------- packages/types/src/primitive/Generic/Event.ts | 4 +- packages/types/src/scripts/MetadataMd.ts | 2 +- 10 files changed, 69 insertions(+), 222 deletions(-) diff --git a/packages/api-metadata/src/consts/fromMetadata/index.ts b/packages/api-metadata/src/consts/fromMetadata/index.ts index b9633264dd..8acd7df898 100644 --- a/packages/api-metadata/src/consts/fromMetadata/index.ts +++ b/packages/api-metadata/src/consts/fromMetadata/index.ts @@ -14,7 +14,7 @@ import { stringCamelCase } from '@polkadot/util'; * @param metadata - The metadata */ export default function fromMetadata (metadata: Metadata): Constants { - return metadata.asV7.modules.reduce((result, moduleMetadata): Constants => { + return metadata.asLatest.modules.reduce((result, moduleMetadata): Constants => { if (moduleMetadata.constants.isEmpty) { return result; } diff --git a/packages/api-metadata/src/extrinsics/fromMetadata/index.ts b/packages/api-metadata/src/extrinsics/fromMetadata/index.ts index 54947c8dc7..e615077367 100644 --- a/packages/api-metadata/src/extrinsics/fromMetadata/index.ts +++ b/packages/api-metadata/src/extrinsics/fromMetadata/index.ts @@ -17,8 +17,8 @@ import createUnchecked from './createUnchecked'; * @param metadata - The metadata */ export default function fromMetadata (metadata: Metadata): ModulesWithCalls { - return metadata.asV7.modules - .filter((modul): boolean => modul.calls.isSome) + return metadata.asLatest.modules + .filter(({ calls }): boolean => calls.isSome) .reduce((result, modul: ModuleMetadata, sectionIndex): ModulesWithCalls => { const section = stringCamelCase(modul.name.toString()); diff --git a/packages/api-metadata/src/storage/fromMetadata/index.ts b/packages/api-metadata/src/storage/fromMetadata/index.ts index 349a8a45da..6121e75a3d 100644 --- a/packages/api-metadata/src/storage/fromMetadata/index.ts +++ b/packages/api-metadata/src/storage/fromMetadata/index.ts @@ -16,7 +16,7 @@ import { storage } from './storage'; * @param metadata - The metadata */ export default function fromMetadata (metadata: Metadata): Storage { - return metadata.asV7.modules.reduce((result, moduleMetadata): Storage => { + return metadata.asLatest.modules.reduce((result, moduleMetadata): Storage => { if (moduleMetadata.storage.isNone) { return result; } diff --git a/packages/types/src/Metadata/MetadataVersioned.ts b/packages/types/src/Metadata/MetadataVersioned.ts index 61ffdf19b0..6ef950bcff 100644 --- a/packages/types/src/Metadata/MetadataVersioned.ts +++ b/packages/types/src/Metadata/MetadataVersioned.ts @@ -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 { assert, isUndefined } from '@polkadot/util'; +import { assert } from '@polkadot/util'; import Enum from '../codec/Enum'; import Struct from '../codec/Struct'; @@ -23,6 +23,10 @@ import v4ToV5 from './v4/toV5'; import v5ToV6 from './v5/toV6'; import v6ToV7 from './v6/toV7'; +type MetaMapped = MetadataV0 | MetadataV1 | MetadataV2 | MetadataV3 | MetadataV4 | MetadataV5 | MetadataV6 | MetadataV7; +type MetaVersions = 1 | 2 | 3 | 4 | 5 | 6 | 7; +type MetaAsX = 'asV0' | 'asV1' | 'asV2' | 'asV3' | 'asV4' | 'asV5' | 'asV6'; + class MetadataEnum extends Enum { public constructor (value?: any) { super({ @@ -186,19 +190,7 @@ class MetadataEnum extends Enum { * The versioned runtime metadata as a decoded structure */ export default class MetadataVersioned extends Struct { - private _convertedV1?: MetadataV1; - - private _convertedV2?: MetadataV2; - - private _convertedV3?: MetadataV3; - - private _convertedV4?: MetadataV4; - - private _convertedV5?: MetadataV5; - - private _convertedV6?: MetadataV6; - - private _convertedV7?: MetadataV7; + private _converted: Map = new Map(); public constructor (value?: any) { super({ @@ -207,6 +199,27 @@ export default class MetadataVersioned extends Struct { }, value); } + private assertVersion (version: number): boolean { + assert(this.metadata.version <= version, `Cannot convert metadata from v${this.metadata.version} to v${version}`); + + return this.version === version; + } + + private getVersion (version: MetaVersions, fromPrev: (input: F) => T): T { + const asCurr: MetaAsX = `asV${version}` as any; + const asPrev: MetaAsX = `asV${version - 1}` as any; + + if (this.assertVersion(version)) { + return this.metadata[asCurr] as T; + } + + if (!this._converted.has(version)) { + this._converted.set(version, fromPrev(this[asPrev] as F)); + } + + return this._converted.get(version) as T; + } + /** * @description */ @@ -232,7 +245,7 @@ export default class MetadataVersioned extends Struct { * @description Returns the wrapped metadata as a V0 object */ public get asV0 (): MetadataV0 { - assert(this.metadata.version === 0, `Cannot convert metadata from v${this.metadata.version} to v0`); + this.assertVersion(0); return this.metadata.asV0; } @@ -241,122 +254,59 @@ export default class MetadataVersioned extends Struct { * @description Returns the wrapped values as a V1 object */ public get asV1 (): MetadataV1 { - assert(this.metadata.version <= 1, `Cannot convert metadata from v${this.metadata.version} to v1`); - - if (this.metadata.version === 1) { - return this.metadata.asV1; - } - - if (isUndefined(this._convertedV1)) { - this._convertedV1 = v0ToV1(this.asV0); - } - - return this._convertedV1; + return this.getVersion(1, v0ToV1); } /** * @description Returns the wrapped values as a V2 object */ public get asV2 (): MetadataV2 { - assert(this.metadata.version <= 2, `Cannot convert metadata from v${this.metadata.version} to v2`); - - if (this.metadata.version === 2) { - return this.metadata.asV2; - } - - if (isUndefined(this._convertedV2)) { - this._convertedV2 = v1ToV2(this.asV1); - } - - return this._convertedV2; + return this.getVersion(2, v1ToV2); } /** * @description Returns the wrapped values as a V3 object */ public get asV3 (): MetadataV3 { - assert(this.metadata.version <= 3, `Cannot convert metadata from v${this.metadata.version} to v3`); - - if (this.metadata.version === 3) { - return this.metadata.asV3; - } - - if (isUndefined(this._convertedV3)) { - this._convertedV3 = v2ToV3(this.asV2); - } - - return this._convertedV3; + return this.getVersion(3, v2ToV3); } /** * @description Returns the wrapped values as a V4 object */ public get asV4 (): MetadataV4 { - assert(this.metadata.version <= 4, `Cannot convert metadata from v${this.metadata.version} to v4`); - - if (this.metadata.version === 4) { - return this.metadata.asV4; - } - - if (isUndefined(this._convertedV4)) { - this._convertedV4 = v3ToV4(this.asV3); - } - - return this._convertedV4; + return this.getVersion(4, v3ToV4); } /** * @description Returns the wrapped values as a V5 object */ public get asV5 (): MetadataV5 { - assert(this.metadata.version <= 5, `Cannot convert metadata from v${this.metadata.version} to v5`); - - if (this.metadata.version === 5) { - return this.metadata.asV5; - } - - if (isUndefined(this._convertedV5)) { - this._convertedV5 = v4ToV5(this.asV4); - } - - return this._convertedV5; + return this.getVersion(5, v4ToV5); } /** * @description Returns the wrapped values as a V6 object */ public get asV6 (): MetadataV6 { - assert(this.metadata.version <= 6, `Cannot convert metadata from v${this.metadata.version} to v6`); - - if (this.metadata.version === 6) { - return this.metadata.asV6; - } - - if (isUndefined(this._convertedV6)) { - this._convertedV6 = v5ToV6(this.asV5); - } - - return this._convertedV6; + return this.getVersion(6, v5ToV6); } /** * @description Returns the wrapped values as a V7 object */ public get asV7 (): MetadataV7 { - assert(this.metadata.version <= 7, `Cannot convert metadata from v${this.metadata.version} to v7`); + return this.getVersion(7, v6ToV7); + } - if (this.metadata.version === 7) { - return this.metadata.asV7; - } - - if (isUndefined(this._convertedV7)) { - this._convertedV7 = v6ToV7(this.asV6); - } - - return this._convertedV7; + /** + * @description Returns the wrapped values as a latest version object + */ + public get asLatest (): MetadataV7 { + return this.asV7; } public getUniqTypes (throwError: boolean): string[] { - return this.asV7.getUniqTypes(throwError); + return this.asLatest.getUniqTypes(throwError); } } diff --git a/packages/types/src/Metadata/util/testUtil.ts b/packages/types/src/Metadata/util/testUtil.ts index eda5a403ab..3c61c3fe01 100644 --- a/packages/types/src/Metadata/util/testUtil.ts +++ b/packages/types/src/Metadata/util/testUtil.ts @@ -56,7 +56,7 @@ export function defaultValues (rpcData: string): void { Call.injectMethods(extrinsicsFromMeta(metadata)); - metadata.asV7.modules + metadata.asLatest.modules .filter(({ storage }): boolean => storage.isSome) .forEach((mod): void => { mod.storage.unwrap().items.forEach(({ fallback, name, type }): void => { diff --git a/packages/types/src/primitive/Extrinsic/v1/ExtrinsicSignature.ts b/packages/types/src/primitive/Extrinsic/v1/ExtrinsicSignature.ts index 353b17d6af..198597eb9b 100644 --- a/packages/types/src/primitive/Extrinsic/v1/ExtrinsicSignature.ts +++ b/packages/types/src/primitive/Extrinsic/v1/ExtrinsicSignature.ts @@ -12,7 +12,7 @@ import Struct from '../../../codec/Struct'; import Call from '../../Generic/Call'; import ExtrinsicEra from '../ExtrinsicEra'; import { EMPTY_U8A, IMMORTAL_ERA } from '../constants'; -import ExtrinsicPayload from './ExtrinsicPayload'; +import ExtrinsicPayloadV1 from './ExtrinsicPayload'; /** * @name ExtrinsicSignature @@ -97,7 +97,7 @@ export default class ExtrinsicSignatureV1 extends Struct implements IExtrinsicSi return createType('Compact', 0); } - private injectSignature (signer: Address, signature: Signature, { era, nonce }: ExtrinsicPayload): IExtrinsicSignature { + private injectSignature (signer: Address, signature: Signature, { era, nonce }: ExtrinsicPayloadV1): IExtrinsicSignature { this.set('era', era); this.set('nonce', nonce); this.set('signer', signer); @@ -113,7 +113,7 @@ export default class ExtrinsicSignatureV1 extends Struct implements IExtrinsicSi return this.injectSignature( createType('Address', signer), createType('Signature', signature), - new ExtrinsicPayload(payload) + new ExtrinsicPayloadV1(payload) ); } @@ -122,7 +122,7 @@ export default class ExtrinsicSignatureV1 extends Struct implements IExtrinsicSi */ public sign (method: Call, account: IKeyringPair, { blockHash, era, genesisHash, nonce }: SignatureOptions): IExtrinsicSignature { const signer = createType('Address', account.publicKey); - const payload = new ExtrinsicPayload({ + const payload = new ExtrinsicPayloadV1({ blockHash, era: era || IMMORTAL_ERA, genesisHash, diff --git a/packages/types/src/primitive/Extrinsic/v2/ExtrinsicSignature.ts b/packages/types/src/primitive/Extrinsic/v2/ExtrinsicSignature.ts index 7a0fa2e336..8b71952a0f 100644 --- a/packages/types/src/primitive/Extrinsic/v2/ExtrinsicSignature.ts +++ b/packages/types/src/primitive/Extrinsic/v2/ExtrinsicSignature.ts @@ -11,9 +11,9 @@ import Compact from '../../../codec/Compact'; import Struct from '../../../codec/Struct'; import Call from '../../Generic/Call'; import ExtrinsicEra from '../ExtrinsicEra'; -import ExtrinsicPayload from './ExtrinsicPayload'; import { EMPTY_U8A, IMMORTAL_ERA } from '../constants'; -import ExtrinsicExtra from '../v2/ExtrinsicExtra'; +import ExtrinsicExtraV2 from './ExtrinsicExtra'; +import ExtrinsicPayloadV2 from './ExtrinsicPayload'; /** * @name ExtrinsicSignature @@ -25,7 +25,7 @@ export default class ExtrinsicSignatureV2 extends Struct implements IExtrinsicSi super({ signer: 'Address', signature: 'Signature', - extra: ExtrinsicExtra + extra: ExtrinsicExtraV2 }, ExtrinsicSignatureV2.decodeExtrinsicSignature(value, isSigned)); } @@ -60,8 +60,8 @@ export default class ExtrinsicSignatureV2 extends Struct implements IExtrinsicSi /** * @description Returns the extra extrinsic info */ - public get extra (): ExtrinsicExtra { - return this.get('extra') as ExtrinsicExtra; + public get extra (): ExtrinsicExtraV2 { + return this.get('extra') as ExtrinsicExtraV2; } /** @@ -99,7 +99,7 @@ export default class ExtrinsicSignatureV2 extends Struct implements IExtrinsicSi return this.extra.tip; } - private injectSignature (signer: Address, signature: Signature, { era, nonce, tip }: ExtrinsicPayload): IExtrinsicSignature { + protected injectSignature (signer: Address, signature: Signature, { era, nonce, tip }: ExtrinsicPayloadV2): IExtrinsicSignature { this.extra.set('era', era); this.extra.set('nonce', nonce); this.extra.set('tip', tip); @@ -117,7 +117,7 @@ export default class ExtrinsicSignatureV2 extends Struct implements IExtrinsicSi return this.injectSignature( createType('Address', signer), createType('Signature', signature), - new ExtrinsicPayload(payload) + new ExtrinsicPayloadV2(payload) ); } @@ -126,7 +126,7 @@ export default class ExtrinsicSignatureV2 extends Struct implements IExtrinsicSi */ public sign (method: Call, account: IKeyringPair, { blockHash, era, genesisHash, nonce, tip }: SignatureOptions): IExtrinsicSignature { const signer = createType('Address', account.publicKey); - const payload = new ExtrinsicPayload({ + const payload = new ExtrinsicPayloadV2({ blockHash, era: era || IMMORTAL_ERA, genesisHash, diff --git a/packages/types/src/primitive/Extrinsic/v3/ExtrinsicSignature.ts b/packages/types/src/primitive/Extrinsic/v3/ExtrinsicSignature.ts index 4978c676cc..d5f115c319 100644 --- a/packages/types/src/primitive/Extrinsic/v3/ExtrinsicSignature.ts +++ b/packages/types/src/primitive/Extrinsic/v3/ExtrinsicSignature.ts @@ -2,114 +2,21 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { Address, Balance, Index, Signature } from '../../../interfaces/runtime'; +import { Address } from '../../../interfaces/runtime'; import { ExtrinsicPayloadValue, IExtrinsicSignature, IKeyringPair, SignatureOptions } from '../../../types'; -import { ExtrinsicSignatureOptions } from '../types'; import { createType } from '../../../codec/create'; -import Compact from '../../../codec/Compact'; -import Struct from '../../../codec/Struct'; import Call from '../../Generic/Call'; -import ExtrinsicEra from '../ExtrinsicEra'; -import ExtrinsicPayload from './ExtrinsicPayload'; -import { EMPTY_U8A, IMMORTAL_ERA } from '../constants'; -import ExtrinsicExtra from '../v2/ExtrinsicExtra'; +import { IMMORTAL_ERA } from '../constants'; +import ExtrinsicSignatureV2 from '../v2/ExtrinsicSignature'; +import ExtrinsicPayloadV3 from './ExtrinsicPayload'; /** * @name ExtrinsicSignatureV3 * @description * A container for the [[Signature]] associated with a specific [[Extrinsic]] */ -export default class ExtrinsicSignatureV3 extends Struct implements IExtrinsicSignature { - public constructor (value: ExtrinsicSignatureV3 | Uint8Array | undefined, { isSigned }: ExtrinsicSignatureOptions = {}) { - super({ - signer: 'Address', - signature: 'Signature', - extra: ExtrinsicExtra - }, ExtrinsicSignatureV3.decodeExtrinsicSignature(value, isSigned)); - } - - public static decodeExtrinsicSignature (value: ExtrinsicSignatureV3 | Uint8Array | undefined, isSigned: boolean = false): ExtrinsicSignatureV3 | Uint8Array { - if (!value) { - return EMPTY_U8A; - } else if (value instanceof ExtrinsicSignatureV3) { - return value; - } - - return isSigned - ? value - : EMPTY_U8A; - } - - /** - * @description The length of the value when encoded as a Uint8Array - */ - public get encodedLength (): number { - return this.isSigned - ? super.encodedLength - : 0; - } - - /** - * @description `true` if the signature is valid - */ - public get isSigned (): boolean { - return !this.signature.isEmpty; - } - - /** - * @description Returns the extra extrinsic info - */ - public get extra (): ExtrinsicExtra { - return this.get('extra') as ExtrinsicExtra; - } - - /** - * @description The [[ExtrinsicEra]] (mortal or immortal) this signature applies to - */ - public get era (): ExtrinsicEra { - return this.extra.era; - } - - /** - * @description The [[Index]] for the signature - */ - public get nonce (): Compact { - return this.extra.nonce; - } - - /** - * @description The actuall [[Signature]] hash - */ - public get signature (): Signature { - return this.get('signature') as Signature; - } - - /** - * @description The [[Address]] that signed - */ - public get signer (): Address { - return this.get('signer') as Address; - } - - /** - * @description The [[Balance]] tip - */ - public get tip (): Compact { - return this.extra.tip; - } - - private injectSignature (signer: Address, signature: Signature, { era, nonce, tip }: ExtrinsicPayload): IExtrinsicSignature { - this.extra.set('era', era); - this.extra.set('nonce', nonce); - this.extra.set('tip', tip); - - this.set('signer', signer); - this.set('signature', signature); - - return this; - } - +export default class ExtrinsicSignatureV3 extends ExtrinsicSignatureV2 { /** * @description Adds a raw signature */ @@ -117,7 +24,7 @@ export default class ExtrinsicSignatureV3 extends Struct implements IExtrinsicSi return this.injectSignature( createType('Address', signer), createType('Signature', signature), - new ExtrinsicPayload(payload) + new ExtrinsicPayloadV3(payload) ); } @@ -126,7 +33,7 @@ export default class ExtrinsicSignatureV3 extends Struct implements IExtrinsicSi */ public sign (method: Call, account: IKeyringPair, { blockHash, era, genesisHash, nonce, tip }: SignatureOptions): IExtrinsicSignature { const signer = createType('Address', account.publicKey); - const payload = new ExtrinsicPayload({ + const payload = new ExtrinsicPayloadV3({ blockHash, era: era || IMMORTAL_ERA, genesisHash, @@ -138,14 +45,4 @@ export default class ExtrinsicSignatureV3 extends Struct implements IExtrinsicSi return this.injectSignature(signer, signature, payload); } - - /** - * @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 { - return this.isSigned - ? super.toU8a(isBare) - : EMPTY_U8A; - } } diff --git a/packages/types/src/primitive/Generic/Event.ts b/packages/types/src/primitive/Generic/Event.ts index 10d5f466b2..79fda8fb0c 100644 --- a/packages/types/src/primitive/Generic/Event.ts +++ b/packages/types/src/primitive/Generic/Event.ts @@ -111,8 +111,8 @@ export default class Event extends Struct { // This is called/injected by the API on init, allowing a snapshot of // the available system events to be used in lookups public static injectMetadata (metadata: Metadata): void { - metadata.asV7.modules - .filter((section): boolean => section.events.isSome) + metadata.asLatest.modules + .filter(({ events }): boolean => events.isSome) .forEach((section, sectionIndex): void => { const sectionName = stringCamelCase(section.name.toString()); diff --git a/packages/types/src/scripts/MetadataMd.ts b/packages/types/src/scripts/MetadataMd.ts index 5fc8628588..3e53b4469f 100644 --- a/packages/types/src/scripts/MetadataMd.ts +++ b/packages/types/src/scripts/MetadataMd.ts @@ -241,7 +241,7 @@ function writeToEventsMd (metadata: MetadataV7): void { writeFile('docs/METHODS_EVENTS.md', addEvents(metadata)); } -const metadata = new Metadata(rpcdata).asV7; +const metadata = new Metadata(rpcdata).asLatest; writeToRpcMd(); writeToConstantsMd(metadata);