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
// `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 => {
+4 -1
View File
@@ -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<ExtrinsicPayload>': Option<ExtrinsicPayload>;
'Vec<ExtrinsicPayload>': Vec<ExtrinsicPayload>;
ExtrinsicUnknown: ExtrinsicUnknown;
'Option<ExtrinsicUnknown>': Option<ExtrinsicUnknown>;
'Vec<ExtrinsicUnknown>': Vec<ExtrinsicUnknown>;
Hash: Hash;
'Option<Hash>': Option<Hash>;
'Vec<Hash>': Vec<Hash>;
@@ -20,6 +20,7 @@ export default {
Extrinsic: 'GenericExtrinsic',
ExtrinsicEra: 'GenericExtrinsicEra',
ExtrinsicPayload: 'GenericExtrinsicPayload',
ExtrinsicUnknown: 'GenericExtrinsicUnknown',
Hash: 'H256',
Header: {
parentHash: 'Hash',
@@ -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;
@@ -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<ExtrinsicV1 | ExtrinsicV2 | ExtrinsicV3> implements IExtrinsic {
public constructor (value: Extrinsic | ExtrinsicValue | AnyU8a | Call | undefined, { version }: ExtrinsicOptions = {}) {
export default class Extrinsic extends Base<ExtrinsicVx | ExtrinsicUnknown> 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<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
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]);
}
@@ -127,7 +133,7 @@ export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
* @description The era for thios extrinsic
*/
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
*/
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
*/
public get method (): Call {
return this.raw.method;
return (this.raw as ExtrinsicVx).method;
}
/**
* @description The nonce for this extrinsic
*/
public get nonce (): Compact<Index> {
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<Balance> {
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<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
};
}
this.raw.addSignature(signer, signature, payload);
(this.raw as ExtrinsicVx).addSignature(signer, signature, payload);
return this;
}
@@ -247,7 +253,7 @@ export default class Extrinsic extends Base<ExtrinsicV1 | ExtrinsicV2 | Extrinsi
* @description Sign the extrinsic with a specific keypair
*/
public sign (account: IKeyringPair, options: SignatureOptions): Extrinsic {
this.raw.sign(account, options);
(this.raw as ExtrinsicVx).sign(account, options);
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 GenericExtrinsicEra, MortalEra as GenericMortalEra, ImmortalEra as GenericImmortalEra } from './ExtrinsicEra';
export { default as GenericExtrinsicPayload } from './ExtrinsicPayload';
export { default as GenericExtrinsicUnknown } from './ExtrinsicUnknown';
@@ -5,7 +5,8 @@
import { AnyNumber } from '../../types';
export interface ExtrinsicOptions {
isSigned?: boolean;
isSigned: boolean;
version: number;
}
export interface ExtrinsicSignatureOptions {
@@ -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<ExtrinsicOptions> = {}) {
super({
signature: ExtrinsicSignatureV1,
method: 'Call'
@@ -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<ExtrinsicOptions> = {}) {
super({
signature: ExtrinsicSignatureV2,
method: 'Call'
@@ -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<ExtrinsicOptions> = {}) {
super({
signature: ExtrinsicSignatureV3,
method: 'Call'