diff --git a/packages/types/src/index.spec.ts b/packages/types/src/index.spec.ts index 124d905946..b7027fff00 100644 --- a/packages/types/src/index.spec.ts +++ b/packages/types/src/index.spec.ts @@ -16,7 +16,11 @@ import * as definitions from './interfaces/definitions'; // specifically for the types that _should_ throw in the constrtuctor, i.e // `usize` is not allowed (runtime incompat) and `origin` is not passed through // to any calls. All other types _must_ pass and allow for empty defaults -const UNCONSTRUCTABLE = ['genericorigin', 'origin', 'usize']; +const UNCONSTRUCTABLE = [ + 'ExtrinsicUnknown', 'GenericExtrinsicUnknown', + 'GenericOrigin', 'Origin', + 'usize' +].map((v): string => v.toLowerCase()); function testTypes (type: string, typeNames: string[]): void { describe(type, (): void => { diff --git a/packages/types/src/interfaceRegistry.ts b/packages/types/src/interfaceRegistry.ts index a030b1132e..c30b0541b0 100644 --- a/packages/types/src/interfaceRegistry.ts +++ b/packages/types/src/interfaceRegistry.ts @@ -3,7 +3,7 @@ import { Compact, Option, Vec } from './codec'; import { Bytes, Data, Fixed64, H160, H256, H512, Null, StorageData, StorageHasher, StorageKey, Text, Type, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from './primitive'; -import { AccountId, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, Call, Consensus, ConsensusEngineId, Digest, DigestItem, Ed25519Signature, Extrinsic, ExtrinsicEra, ExtrinsicPayload, Hash, Header, ImmortalEra, Index, Justification, KeyTypeId, KeyValue, LockIdentifier, Moment, MortalEra, Origin, Perbill, Permill, Phantom, PhantomData, PreRuntime, Seal, SealV0, Signature, SignedBlock, Sr25519Signature, ValidatorId, Weight, WeightMultiplier } from './interfaces/runtime'; +import { AccountId, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, Call, Consensus, ConsensusEngineId, Digest, DigestItem, Ed25519Signature, Extrinsic, ExtrinsicEra, ExtrinsicPayload, ExtrinsicUnknown, Hash, Header, ImmortalEra, Index, Justification, KeyTypeId, KeyValue, LockIdentifier, Moment, MortalEra, Origin, Perbill, Permill, Phantom, PhantomData, PreRuntime, Seal, SealV0, Signature, SignedBlock, Sr25519Signature, ValidatorId, Weight, WeightMultiplier } from './interfaces/runtime'; import { InclusionHeight, Uncle, UncleEntryItem } from './interfaces/authorship'; import { RawAuraPreDigest } from './interfaces/aura'; import { BabeAuthorityWeight, BabeBlockWeight, BabeWeight, RawBabePreDigest, RawBabePreDigestPrimary, RawBabePreDigestSecondary, SlotNumber } from './interfaces/babe'; @@ -167,6 +167,9 @@ export interface InterfaceRegistry { ExtrinsicPayload: ExtrinsicPayload; 'Option': Option; 'Vec': Vec; + ExtrinsicUnknown: ExtrinsicUnknown; + 'Option': Option; + 'Vec': Vec; Hash: Hash; 'Option': Option; 'Vec': Vec; diff --git a/packages/types/src/interfaces/runtime/definitions.ts b/packages/types/src/interfaces/runtime/definitions.ts index b649b7186f..0485b1c6ae 100644 --- a/packages/types/src/interfaces/runtime/definitions.ts +++ b/packages/types/src/interfaces/runtime/definitions.ts @@ -20,6 +20,7 @@ export default { Extrinsic: 'GenericExtrinsic', ExtrinsicEra: 'GenericExtrinsicEra', ExtrinsicPayload: 'GenericExtrinsicPayload', + ExtrinsicUnknown: 'GenericExtrinsicUnknown', Hash: 'H256', Header: { parentHash: 'Hash', diff --git a/packages/types/src/interfaces/runtime/types.ts b/packages/types/src/interfaces/runtime/types.ts index 73ee7ff94e..b637b2869e 100644 --- a/packages/types/src/interfaces/runtime/types.ts +++ b/packages/types/src/interfaces/runtime/types.ts @@ -3,7 +3,7 @@ import { Codec } from '../../types'; import { Compact, Struct } from '../../codec'; -import { Bytes, Fixed64, GenericAccountId, GenericAccountIndex, GenericAddress, GenericBlock, GenericCall, GenericConsensusEngineId, GenericDigest, GenericDigestItem, GenericExtrinsic, GenericExtrinsicEra, GenericExtrinsicPayload, GenericImmortalEra, GenericMortalEra, GenericOrigin, H256, H512, Null, StorageData, StorageKey, u128, u32, u64 } from '../../primitive'; +import { Bytes, Fixed64, GenericAccountId, GenericAccountIndex, GenericAddress, GenericBlock, GenericCall, GenericConsensusEngineId, GenericDigest, GenericDigestItem, GenericExtrinsic, GenericExtrinsicEra, GenericExtrinsicPayload, GenericExtrinsicUnknown, GenericImmortalEra, GenericMortalEra, GenericOrigin, H256, H512, Null, StorageData, StorageKey, u128, u32, u64 } from '../../primitive'; /** GenericAccountId */ export type AccountId = GenericAccountId; @@ -59,6 +59,9 @@ export type ExtrinsicEra = GenericExtrinsicEra; /** GenericExtrinsicPayload */ export type ExtrinsicPayload = GenericExtrinsicPayload; +/** GenericExtrinsicUnknown */ +export type ExtrinsicUnknown = GenericExtrinsicUnknown; + /** H256 */ export type Hash = H256; diff --git a/packages/types/src/primitive/Extrinsic/Extrinsic.ts b/packages/types/src/primitive/Extrinsic/Extrinsic.ts index 86fd105796..cc9ae72820 100644 --- a/packages/types/src/primitive/Extrinsic/Extrinsic.ts +++ b/packages/types/src/primitive/Extrinsic/Extrinsic.ts @@ -3,12 +3,13 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { FunctionMetadataV7 } from '../../interfaces/metadata/types'; -import { Address, Balance, Call, Index } from '../../interfaces/runtime'; +import { Address, Balance, Call, ExtrinsicUnknown, Index } from '../../interfaces/runtime'; import { AnyU8a, ArgsDef, Codec, ExtrinsicPayloadValue, IExtrinsic, IHash, IKeyringPair, SignatureOptions } from '../../types'; +import { ExtrinsicOptions } from './types'; import { assert, isHex, isU8a, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util'; -import { ClassOf } from '../../codec/create'; +import { createType, ClassOf } from '../../codec/create'; import Base from '../../codec/Base'; import Compact from '../../codec/Compact'; import ExtrinsicV1, { ExtrinsicValueV1 } from './v1/Extrinsic'; @@ -17,9 +18,13 @@ import ExtrinsicV3, { ExtrinsicValueV3 } from './v3/Extrinsic'; import ExtrinsicEra from './ExtrinsicEra'; import { BIT_SIGNED, BIT_UNSIGNED, DEFAULT_VERSION, UNMASK_VERSION } from './constants'; +// We use this type internally to cast the raw value since ExtrinsicUnknown does not actually properly +// implement an Extrinsic - by design, it just throws on construction, allowing for overrides +type ExtrinsicVx = ExtrinsicV1 | ExtrinsicV2 | ExtrinsicV3; + type ExtrinsicValue = ExtrinsicValueV1 | ExtrinsicValueV2 | ExtrinsicValueV3; -interface ExtrinsicOptions { +interface CreateOptions { version?: number; } @@ -35,28 +40,29 @@ interface ExtrinsicOptions { * - signed, to create a transaction * - left as is, to create an inherent */ -export default class Extrinsic extends Base implements IExtrinsic { - public constructor (value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, { version }: ExtrinsicOptions = {}) { +export default class Extrinsic extends Base implements IExtrinsic { + public constructor (value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, { version }: CreateOptions = {}) { super(Extrinsic.decodeExtrinsic(value, version)); } - private static newFromValue (value: any, version: number): ExtrinsicV1 | ExtrinsicV2 | ExtrinsicV3 { + private static newFromValue (value: any, version: number): ExtrinsicVx | ExtrinsicUnknown { if (value instanceof Extrinsic) { return value.raw; } const isSigned = (version & BIT_SIGNED) === BIT_SIGNED; const type = version & UNMASK_VERSION; + const options: ExtrinsicOptions = { isSigned, version }; switch (type) { - case 1: return new ExtrinsicV1(value, { isSigned }); - case 2: return new ExtrinsicV2(value, { isSigned }); - case 3: return new ExtrinsicV3(value, { isSigned }); - default: throw new Error(`Unsupported extrinsic version ${type}`); + case 1: return new ExtrinsicV1(value, options); + case 2: return new ExtrinsicV2(value, options); + case 3: return new ExtrinsicV3(value, options); + default: return createType('ExtrinsicUnknown', value, options); } } - public static decodeExtrinsic (value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, version: number = DEFAULT_VERSION): ExtrinsicV1 | ExtrinsicV2 | ExtrinsicV3 { + public static decodeExtrinsic (value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, version: number = DEFAULT_VERSION): ExtrinsicVx | ExtrinsicUnknown { if (Array.isArray(value) || isHex(value)) { // Instead of the block below, it should simply be: // return Extrinsic.decodeExtrinsic(hexToU8a(value as string)); @@ -91,7 +97,7 @@ export default class Extrinsic extends Base { - return this.raw.signature.nonce; + return (this.raw as ExtrinsicVx).signature.nonce; } /** * @description The [[ExtrinsicSignature]] */ public get signature (): IHash { - return this.raw.signature.signature; + return (this.raw as ExtrinsicVx).signature.signature; } /** * @description The [[Address]] that signed */ public get signer (): Address { - return this.raw.signature.signer; + return (this.raw as ExtrinsicVx).signature.signer; } /** * @description Forwards compat */ public get tip (): Compact { - return this.raw.signature.tip; + return (this.raw as ExtrinsicVx).signature.tip; } /** * @description Returns the raw transaction version (not flagged with signing information) */ public get type (): number { - return this.raw.version; + return (this.raw as ExtrinsicVx).version; } /** @@ -238,7 +244,7 @@ export default class Extrinsic extends Base = {}) { + super({}); + + throw new Error(`Unsupported ${isSigned ? '' : 'un'}signed extrinsic version ${version & UNMASK_VERSION}`); + } +} diff --git a/packages/types/src/primitive/Extrinsic/index.ts b/packages/types/src/primitive/Extrinsic/index.ts index 7ff156a5c6..ffa0998cd5 100644 --- a/packages/types/src/primitive/Extrinsic/index.ts +++ b/packages/types/src/primitive/Extrinsic/index.ts @@ -5,3 +5,4 @@ export { default as GenericExtrinsic } from './Extrinsic'; export { default as GenericExtrinsicEra, MortalEra as GenericMortalEra, ImmortalEra as GenericImmortalEra } from './ExtrinsicEra'; export { default as GenericExtrinsicPayload } from './ExtrinsicPayload'; +export { default as GenericExtrinsicUnknown } from './ExtrinsicUnknown'; diff --git a/packages/types/src/primitive/Extrinsic/types.ts b/packages/types/src/primitive/Extrinsic/types.ts index 66388556bd..8c1849aeeb 100644 --- a/packages/types/src/primitive/Extrinsic/types.ts +++ b/packages/types/src/primitive/Extrinsic/types.ts @@ -5,7 +5,8 @@ import { AnyNumber } from '../../types'; export interface ExtrinsicOptions { - isSigned?: boolean; + isSigned: boolean; + version: number; } export interface ExtrinsicSignatureOptions { diff --git a/packages/types/src/primitive/Extrinsic/v1/Extrinsic.ts b/packages/types/src/primitive/Extrinsic/v1/Extrinsic.ts index d895aaa3a8..1f984d4758 100644 --- a/packages/types/src/primitive/Extrinsic/v1/Extrinsic.ts +++ b/packages/types/src/primitive/Extrinsic/v1/Extrinsic.ts @@ -25,7 +25,7 @@ const TRANSACTION_VERSION = 1; * The first generation of compact extrinsics */ export default class ExtrinsicV1 extends Struct implements IExtrinsicImpl { - public constructor (value?: Uint8Array | ExtrinsicValueV1, { isSigned }: ExtrinsicOptions = {}) { + public constructor (value?: Uint8Array | ExtrinsicValueV1, { isSigned }: Partial = {}) { super({ signature: ExtrinsicSignatureV1, method: 'Call' diff --git a/packages/types/src/primitive/Extrinsic/v2/Extrinsic.ts b/packages/types/src/primitive/Extrinsic/v2/Extrinsic.ts index c688cdf8e5..2a41c61927 100644 --- a/packages/types/src/primitive/Extrinsic/v2/Extrinsic.ts +++ b/packages/types/src/primitive/Extrinsic/v2/Extrinsic.ts @@ -25,7 +25,7 @@ export interface ExtrinsicValueV2 { * The second generation of compact extrinsics */ export default class ExtrinsicV2 extends Struct implements IExtrinsicImpl { - public constructor (value?: Uint8Array | ExtrinsicValueV2 | Call, { isSigned }: ExtrinsicOptions = {}) { + public constructor (value?: Uint8Array | ExtrinsicValueV2 | Call, { isSigned }: Partial = {}) { super({ signature: ExtrinsicSignatureV2, method: 'Call' diff --git a/packages/types/src/primitive/Extrinsic/v3/Extrinsic.ts b/packages/types/src/primitive/Extrinsic/v3/Extrinsic.ts index 03e60c03ea..7796774da5 100644 --- a/packages/types/src/primitive/Extrinsic/v3/Extrinsic.ts +++ b/packages/types/src/primitive/Extrinsic/v3/Extrinsic.ts @@ -22,10 +22,10 @@ export interface ExtrinsicValueV3 { /** * @name ExtrinsicV3 * @description - * The second generation of compact extrinsics + * The third generation of compact extrinsics */ export default class ExtrinsicV3 extends Struct implements IExtrinsicImpl { - public constructor (value?: Uint8Array | ExtrinsicValueV3 | Call, { isSigned }: ExtrinsicOptions = {}) { + public constructor (value?: Uint8Array | ExtrinsicValueV3 | Call, { isSigned }: Partial = {}) { super({ signature: ExtrinsicSignatureV3, method: 'Call'