Pass Extrinsic version, allow ExtrinsicUnknown override (#1348)

* Pass Extrinsic version, allow ExtrinsicUnknown override

* ExtrinsicUnknown should throw
This commit is contained in:
Jaco Greeff
2019-08-29 10:24:39 +02:00
committed by GitHub
parent c2af5b3da9
commit 87f195df2f
11 changed files with 70 additions and 30 deletions
+5 -1
View File
@@ -16,7 +16,11 @@ import * as definitions from './interfaces/definitions';
// specifically for the types that _should_ throw in the constrtuctor, i.e // specifically for the types that _should_ throw in the constrtuctor, i.e
// `usize` is not allowed (runtime incompat) and `origin` is not passed through // `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 // 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 { function testTypes (type: string, typeNames: string[]): void {
describe(type, (): void => { describe(type, (): void => {
+4 -1
View File
@@ -3,7 +3,7 @@
import { Compact, Option, Vec } from './codec'; 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 { 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 { InclusionHeight, Uncle, UncleEntryItem } from './interfaces/authorship';
import { RawAuraPreDigest } from './interfaces/aura'; import { RawAuraPreDigest } from './interfaces/aura';
import { BabeAuthorityWeight, BabeBlockWeight, BabeWeight, RawBabePreDigest, RawBabePreDigestPrimary, RawBabePreDigestSecondary, SlotNumber } from './interfaces/babe'; import { BabeAuthorityWeight, BabeBlockWeight, BabeWeight, RawBabePreDigest, RawBabePreDigestPrimary, RawBabePreDigestSecondary, SlotNumber } from './interfaces/babe';
@@ -167,6 +167,9 @@ export interface InterfaceRegistry {
ExtrinsicPayload: ExtrinsicPayload; ExtrinsicPayload: ExtrinsicPayload;
'Option<ExtrinsicPayload>': Option<ExtrinsicPayload>; 'Option<ExtrinsicPayload>': Option<ExtrinsicPayload>;
'Vec<ExtrinsicPayload>': Vec<ExtrinsicPayload>; 'Vec<ExtrinsicPayload>': Vec<ExtrinsicPayload>;
ExtrinsicUnknown: ExtrinsicUnknown;
'Option<ExtrinsicUnknown>': Option<ExtrinsicUnknown>;
'Vec<ExtrinsicUnknown>': Vec<ExtrinsicUnknown>;
Hash: Hash; Hash: Hash;
'Option<Hash>': Option<Hash>; 'Option<Hash>': Option<Hash>;
'Vec<Hash>': Vec<Hash>; 'Vec<Hash>': Vec<Hash>;
@@ -20,6 +20,7 @@ export default {
Extrinsic: 'GenericExtrinsic', Extrinsic: 'GenericExtrinsic',
ExtrinsicEra: 'GenericExtrinsicEra', ExtrinsicEra: 'GenericExtrinsicEra',
ExtrinsicPayload: 'GenericExtrinsicPayload', ExtrinsicPayload: 'GenericExtrinsicPayload',
ExtrinsicUnknown: 'GenericExtrinsicUnknown',
Hash: 'H256', Hash: 'H256',
Header: { Header: {
parentHash: 'Hash', parentHash: 'Hash',
@@ -3,7 +3,7 @@
import { Codec } from '../../types'; import { Codec } from '../../types';
import { Compact, Struct } from '../../codec'; 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 */ /** GenericAccountId */
export type AccountId = GenericAccountId; export type AccountId = GenericAccountId;
@@ -59,6 +59,9 @@ export type ExtrinsicEra = GenericExtrinsicEra;
/** GenericExtrinsicPayload */ /** GenericExtrinsicPayload */
export type ExtrinsicPayload = GenericExtrinsicPayload; export type ExtrinsicPayload = GenericExtrinsicPayload;
/** GenericExtrinsicUnknown */
export type ExtrinsicUnknown = GenericExtrinsicUnknown;
/** H256 */ /** H256 */
export type Hash = H256; export type Hash = H256;
@@ -3,12 +3,13 @@
// of the Apache-2.0 license. See the LICENSE file for details. // of the Apache-2.0 license. See the LICENSE file for details.
import { FunctionMetadataV7 } from '../../interfaces/metadata/types'; 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 { 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 { 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 Base from '../../codec/Base';
import Compact from '../../codec/Compact'; import Compact from '../../codec/Compact';
import ExtrinsicV1, { ExtrinsicValueV1 } from './v1/Extrinsic'; import ExtrinsicV1, { ExtrinsicValueV1 } from './v1/Extrinsic';
@@ -17,9 +18,13 @@ import ExtrinsicV3, { ExtrinsicValueV3 } from './v3/Extrinsic';
import ExtrinsicEra from './ExtrinsicEra'; import ExtrinsicEra from './ExtrinsicEra';
import { BIT_SIGNED, BIT_UNSIGNED, DEFAULT_VERSION, UNMASK_VERSION } from './constants'; 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; type ExtrinsicValue = ExtrinsicValueV1 | ExtrinsicValueV2 | ExtrinsicValueV3;
interface ExtrinsicOptions { interface CreateOptions {
version?: number; version?: number;
} }
@@ -35,28 +40,29 @@ interface ExtrinsicOptions {
* - signed, to create a transaction * - signed, to create a transaction
* - left as is, to create an inherent * - left as is, to create an inherent
*/ */
export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | ExtrinsicV3> implements IExtrinsic { export default class Extrinsic extends Base<ExtrinsicVx | ExtrinsicUnknown> implements IExtrinsic {
public constructor (value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, { version }: ExtrinsicOptions = {}) { public constructor (value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, { version }: CreateOptions = {}) {
super(Extrinsic.decodeExtrinsic(value, version)); 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) { if (value instanceof Extrinsic) {
return value.raw; return value.raw;
} }
const isSigned = (version & BIT_SIGNED) === BIT_SIGNED; const isSigned = (version & BIT_SIGNED) === BIT_SIGNED;
const type = version & UNMASK_VERSION; const type = version & UNMASK_VERSION;
const options: ExtrinsicOptions = { isSigned, version };
switch (type) { switch (type) {
case 1: return new ExtrinsicV1(value, { isSigned }); case 1: return new ExtrinsicV1(value, options);
case 2: return new ExtrinsicV2(value, { isSigned }); case 2: return new ExtrinsicV2(value, options);
case 3: return new ExtrinsicV3(value, { isSigned }); case 3: return new ExtrinsicV3(value, options);
default: throw new Error(`Unsupported extrinsic version ${type}`); 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)) { if (Array.isArray(value) || isHex(value)) {
// Instead of the block below, it should simply be: // Instead of the block below, it should simply be:
// return Extrinsic.decodeExtrinsic(hexToU8a(value as string)); // return Extrinsic.decodeExtrinsic(hexToU8a(value as string));
@@ -91,7 +97,7 @@ export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
return Extrinsic.newFromValue(value, version); return Extrinsic.newFromValue(value, version);
} }
private static decodeU8a (value: Uint8Array): ExtrinsicV1 | ExtrinsicV2 | ExtrinsicV3 { private static decodeU8a (value: Uint8Array): ExtrinsicVx | ExtrinsicUnknown {
return Extrinsic.newFromValue(value.subarray(1), value[0]); return Extrinsic.newFromValue(value.subarray(1), value[0]);
} }
@@ -127,7 +133,7 @@ export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
* @description The era for thios extrinsic * @description The era for thios extrinsic
*/ */
public get era (): ExtrinsicEra { public get era (): ExtrinsicEra {
return this.raw.signature.era; return (this.raw as ExtrinsicVx).signature.era;
} }
/** /**
@@ -148,7 +154,7 @@ export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
* @description `true` id the extrinsic is signed * @description `true` id the extrinsic is signed
*/ */
public get isSigned (): boolean { public get isSigned (): boolean {
return this.raw.signature.isSigned; return (this.raw as ExtrinsicVx).signature.isSigned;
} }
/** /**
@@ -169,42 +175,42 @@ export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
* @description The [[Call]] this extrinsic wraps * @description The [[Call]] this extrinsic wraps
*/ */
public get method (): Call { public get method (): Call {
return this.raw.method; return (this.raw as ExtrinsicVx).method;
} }
/** /**
* @description The nonce for this extrinsic * @description The nonce for this extrinsic
*/ */
public get nonce (): Compact<Index> { public get nonce (): Compact<Index> {
return this.raw.signature.nonce; return (this.raw as ExtrinsicVx).signature.nonce;
} }
/** /**
* @description The [[ExtrinsicSignature]] * @description The [[ExtrinsicSignature]]
*/ */
public get signature (): IHash { public get signature (): IHash {
return this.raw.signature.signature; return (this.raw as ExtrinsicVx).signature.signature;
} }
/** /**
* @description The [[Address]] that signed * @description The [[Address]] that signed
*/ */
public get signer (): Address { public get signer (): Address {
return this.raw.signature.signer; return (this.raw as ExtrinsicVx).signature.signer;
} }
/** /**
* @description Forwards compat * @description Forwards compat
*/ */
public get tip (): Compact<Balance> { public get tip (): Compact<Balance> {
return this.raw.signature.tip; return (this.raw as ExtrinsicVx).signature.tip;
} }
/** /**
* @description Returns the raw transaction version (not flagged with signing information) * @description Returns the raw transaction version (not flagged with signing information)
*/ */
public get type (): number { public get type (): number {
return this.raw.version; return (this.raw as ExtrinsicVx).version;
} }
/** /**
@@ -238,7 +244,7 @@ export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
}; };
} }
this.raw.addSignature(signer, signature, payload); (this.raw as ExtrinsicVx).addSignature(signer, signature, payload);
return this; return this;
} }
@@ -247,7 +253,7 @@ export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
* @description Sign the extrinsic with a specific keypair * @description Sign the extrinsic with a specific keypair
*/ */
public sign (account: IKeyringPair, options: SignatureOptions): Extrinsic { public sign (account: IKeyringPair, options: SignatureOptions): Extrinsic {
this.raw.sign(account, options); (this.raw as ExtrinsicVx).sign(account, options);
return this; return this;
} }
@@ -0,0 +1,21 @@
// Copyright 2017-2019 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ExtrinsicOptions } from './types';
import Struct from '../../codec/Struct';
import { UNMASK_VERSION } from './constants';
/**
* @name ExtrinsicUnknown
* @description
* A default handler for extrinsics where the version is not known (default throw)
*/
export default class ExtrinsicUnknown extends Struct {
public constructor (value?: any, { isSigned = false, version = 0 }: Partial<ExtrinsicOptions> = {}) {
super({});
throw new Error(`Unsupported ${isSigned ? '' : 'un'}signed extrinsic version ${version & UNMASK_VERSION}`);
}
}
@@ -5,3 +5,4 @@
export { default as GenericExtrinsic } from './Extrinsic'; export { default as GenericExtrinsic } from './Extrinsic';
export { default as GenericExtrinsicEra, MortalEra as GenericMortalEra, ImmortalEra as GenericImmortalEra } from './ExtrinsicEra'; export { default as GenericExtrinsicEra, MortalEra as GenericMortalEra, ImmortalEra as GenericImmortalEra } from './ExtrinsicEra';
export { default as GenericExtrinsicPayload } from './ExtrinsicPayload'; export { default as GenericExtrinsicPayload } from './ExtrinsicPayload';
export { default as GenericExtrinsicUnknown } from './ExtrinsicUnknown';
@@ -5,7 +5,8 @@
import { AnyNumber } from '../../types'; import { AnyNumber } from '../../types';
export interface ExtrinsicOptions { export interface ExtrinsicOptions {
isSigned?: boolean; isSigned: boolean;
version: number;
} }
export interface ExtrinsicSignatureOptions { export interface ExtrinsicSignatureOptions {
@@ -25,7 +25,7 @@ const TRANSACTION_VERSION = 1;
* The first generation of compact extrinsics * The first generation of compact extrinsics
*/ */
export default class ExtrinsicV1 extends Struct implements IExtrinsicImpl { export default class ExtrinsicV1 extends Struct implements IExtrinsicImpl {
public constructor (value?: Uint8Array | ExtrinsicValueV1, { isSigned }: ExtrinsicOptions = {}) { public constructor (value?: Uint8Array | ExtrinsicValueV1, { isSigned }: Partial<ExtrinsicOptions> = {}) {
super({ super({
signature: ExtrinsicSignatureV1, signature: ExtrinsicSignatureV1,
method: 'Call' method: 'Call'
@@ -25,7 +25,7 @@ export interface ExtrinsicValueV2 {
* The second generation of compact extrinsics * The second generation of compact extrinsics
*/ */
export default class ExtrinsicV2 extends Struct implements IExtrinsicImpl { export default class ExtrinsicV2 extends Struct implements IExtrinsicImpl {
public constructor (value?: Uint8Array | ExtrinsicValueV2 | Call, { isSigned }: ExtrinsicOptions = {}) { public constructor (value?: Uint8Array | ExtrinsicValueV2 | Call, { isSigned }: Partial<ExtrinsicOptions> = {}) {
super({ super({
signature: ExtrinsicSignatureV2, signature: ExtrinsicSignatureV2,
method: 'Call' method: 'Call'
@@ -22,10 +22,10 @@ export interface ExtrinsicValueV3 {
/** /**
* @name ExtrinsicV3 * @name ExtrinsicV3
* @description * @description
* The second generation of compact extrinsics * The third generation of compact extrinsics
*/ */
export default class ExtrinsicV3 extends Struct implements IExtrinsicImpl { export default class ExtrinsicV3 extends Struct implements IExtrinsicImpl {
public constructor (value?: Uint8Array | ExtrinsicValueV3 | Call, { isSigned }: ExtrinsicOptions = {}) { public constructor (value?: Uint8Array | ExtrinsicValueV3 | Call, { isSigned }: Partial<ExtrinsicOptions> = {}) {
super({ super({
signature: ExtrinsicSignatureV3, signature: ExtrinsicSignatureV3,
method: 'Call' method: 'Call'