Skip to content

Commit

Permalink
added bitmasks
Browse files Browse the repository at this point in the history
  • Loading branch information
bee344 committed Sep 20, 2024
1 parent d92fa6e commit b4a2f0f
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 28 deletions.
44 changes: 28 additions & 16 deletions packages/types/src/extrinsic/Extrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ import type { Address, Call, CodecHash, Hash } from '../interfaces/runtime/index
import type { MultiLocation } from '../interfaces/types.js';
import type { CallBase, ExtrinsicPayloadValue, ICompact, IExtrinsic, IKeyringPair, INumber, Registry, SignatureOptions } from '../types/index.js';
import type { GenericExtrinsicEra } from './ExtrinsicEra.js';
import type { SubVersionV5 } from './types.js';
import type { Preamble } from './types.js';
import type { ExtrinsicValueV5 } from './v5/Extrinsic.js';

import { AbstractBase } from '@polkadot/types-codec';
import { compactAddLength, compactFromU8a, compactToU8a, isHex, isU8a, objectProperty, objectSpread, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';

import { BIT_SIGNED, BIT_UNSIGNED, DEFAULT_V5_VERSION, DEFAULT_VERSION, LATEST_EXTRINSIC_VERSION, UNMASK_VERSION } from './constants.js';
import { BARE_EXTRINSIC, BIT_SIGNED, BIT_UNSIGNED, DEFAULT_PREAMBLE, DEFAULT_VERSION, GENERAL_EXTRINSIC, LATEST_EXTRINSIC_VERSION, SIGNED_EXTRINSIC, UNMASK_VERSION } from './constants.js';

interface CreateOptions {
version?: number;
subVersionV5?: SubVersionV5;
preamble?: Preamble;
}

// NOTE The following 2 types, as well as the VERSION structure and the latest export
Expand All @@ -37,44 +37,50 @@ const VERSIONS = [
'ExtrinsicV5'
];

const V5_VERSIONS = {
const PREAMBLE = {
bare: 'ExtrinsicV5',
// Not supported yet
general: 'ExtrinsicV5',
signed: 'ExtrinsicV5'
};

const PreambleMask = {
bare: BARE_EXTRINSIC,
general: GENERAL_EXTRINSIC,
signed: SIGNED_EXTRINSIC
}

Check failure on line 51 in packages/types/src/extrinsic/Extrinsic.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

Missing semicolon

export { LATEST_EXTRINSIC_VERSION };

/** @internal */
function newFromValue (registry: Registry, value: any, version: number, subVersionV5: SubVersionV5): ExtrinsicVx | ExtrinsicUnknown {
function newFromValue (registry: Registry, value: any, version: number, preamble: Preamble): ExtrinsicVx | ExtrinsicUnknown {
if (value instanceof GenericExtrinsic) {
return value.unwrap();
}

const isSigned = (version & BIT_SIGNED) === BIT_SIGNED;
const type = (version & UNMASK_VERSION) === 5 ? V5_VERSIONS[subVersionV5] : VERSIONS[version & UNMASK_VERSION] || VERSIONS[0];
const type = (version & UNMASK_VERSION) === 5 ? PREAMBLE[preamble] : VERSIONS[version & UNMASK_VERSION] || VERSIONS[0];

// we cast here since the VERSION definition is incredibly broad - we don't have a
// slice for "only add extrinsic types", and more string definitions become unwieldy
return registry.createTypeUnsafe(type, [value, { isSigned, version }]);
}

/** @internal */
function decodeExtrinsic (registry: Registry, value?: GenericExtrinsic | ExtrinsicValue | AnyU8a | Call, version: number = DEFAULT_VERSION, subVersionV5: SubVersionV5 = DEFAULT_V5_VERSION): ExtrinsicVx | ExtrinsicUnknown {
function decodeExtrinsic (registry: Registry, value?: GenericExtrinsic | ExtrinsicValue | AnyU8a | Call, version: number = DEFAULT_VERSION, preamble: Preamble = DEFAULT_PREAMBLE): ExtrinsicVx | ExtrinsicUnknown {
if (isU8a(value) || Array.isArray(value) || isHex(value)) {
return decodeU8a(registry, u8aToU8a(value), version, subVersionV5);
return decodeU8a(registry, u8aToU8a(value), version, preamble);
} else if (value instanceof registry.createClassUnsafe('Call')) {
return newFromValue(registry, { method: value }, version, subVersionV5);
return newFromValue(registry, { method: value }, version, preamble);
}

return newFromValue(registry, value, version, subVersionV5);
return newFromValue(registry, value, version, preamble);
}

/** @internal */
function decodeU8a (registry: Registry, value: Uint8Array, version: number, subVersionV5: SubVersionV5): ExtrinsicVx | ExtrinsicUnknown {
function decodeU8a (registry: Registry, value: Uint8Array, version: number, preamble: Preamble): ExtrinsicVx | ExtrinsicUnknown {
if (!value.length) {
return newFromValue(registry, new Uint8Array(), version, subVersionV5);
return newFromValue(registry, new Uint8Array(), version, preamble);
}

const [offset, length] = compactFromU8a(value);
Expand All @@ -86,7 +92,7 @@ function decodeU8a (registry: Registry, value: Uint8Array, version: number, subV

const data = value.subarray(offset, total);

return newFromValue(registry, data.subarray(1), data[0], subVersionV5);
return newFromValue(registry, data.subarray(1), data[0], preamble);
}

abstract class ExtrinsicBase<A extends AnyTuple> extends AbstractBase<ExtrinsicVx | ExtrinsicUnknown> {
Expand Down Expand Up @@ -237,7 +243,13 @@ abstract class ExtrinsicBase<A extends AnyTuple> extends AbstractBase<ExtrinsicV
* @description Returns the encoded version flag
*/
public get version (): number {
return this.type | (this.isSigned ? BIT_SIGNED : BIT_UNSIGNED);
if (this.type <= 4) {
console.log('bitmask', this.type | (this.isSigned ? BIT_SIGNED : BIT_UNSIGNED))

Check failure on line 247 in packages/types/src/extrinsic/Extrinsic.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

Missing semicolon
return this.type | (this.isSigned ? BIT_SIGNED : BIT_UNSIGNED)

Check failure on line 248 in packages/types/src/extrinsic/Extrinsic.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

Expected blank line before this statement

Check failure on line 248 in packages/types/src/extrinsic/Extrinsic.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

Missing semicolon
} else {
console.log('bitmask', this.inner.preamble )

Check failure on line 250 in packages/types/src/extrinsic/Extrinsic.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

There should be no space before this paren

Check failure on line 250 in packages/types/src/extrinsic/Extrinsic.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

Missing semicolon
return this.type | PreambleMask[this.inner.preamble];

Check failure on line 251 in packages/types/src/extrinsic/Extrinsic.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

Expected blank line before this statement
}
}

/**
Expand Down Expand Up @@ -269,8 +281,8 @@ export class GenericExtrinsic<A extends AnyTuple = AnyTuple> extends ExtrinsicBa

static LATEST_EXTRINSIC_VERSION = LATEST_EXTRINSIC_VERSION;

constructor (registry: Registry, value?: GenericExtrinsic | ExtrinsicValue | AnyU8a | Call, { subVersionV5, version }: CreateOptions = {}) {
super(registry, decodeExtrinsic(registry, value, registry.metadata.extrinsic.version?.toNumber() || version, subVersionV5));
constructor (registry: Registry, value?: GenericExtrinsic | ExtrinsicValue | AnyU8a | Call, { preamble, version }: CreateOptions = {}) {
super(registry, decodeExtrinsic(registry, value, registry.metadata.extrinsic.version?.toNumber() || version, preamble));
}

/**
Expand Down
16 changes: 8 additions & 8 deletions packages/types/src/extrinsic/ExtrinsicPayload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ import type { ExtrinsicPayloadV5 } from '../interfaces/extrinsics/index.js';
import type { Hash, MultiLocation } from '../interfaces/types.js';
import type { ExtrinsicPayloadValue, ICompact, IKeyringPair, INumber, IOption } from '../types/index.js';
import type { GenericExtrinsicEra } from './ExtrinsicEra.js';
import type { SubVersionV5 } from './types.js';
import type { Preamble } from './types.js';

import { AbstractBase } from '@polkadot/types-codec';
import { hexToU8a, isHex, u8aToHex } from '@polkadot/util';

import { DEFAULT_V5_VERSION, DEFAULT_VERSION } from './constants.js';
import { DEFAULT_PREAMBLE, DEFAULT_VERSION } from './constants.js';

interface ExtrinsicPayloadOptions {
version?: number;
subVersionV5?: SubVersionV5;
pramble?: Preamble;
}

// all our known types that can be returned
Expand All @@ -33,20 +33,20 @@ const VERSIONS = [
'ExtrinsicPayloadV5'
];

const V5_VERSIONS = {
const PREAMBLES = {
bare: 'ExtrinsicPayloadV5',
// Not supported yet
general: 'ExtrinsicPayloadV5',
signed: 'ExtrinsicPayloadV5'
};

/** @internal */
function decodeExtrinsicPayload (registry: Registry, value?: GenericExtrinsicPayload | ExtrinsicPayloadValue | Uint8Array | string, version: number = DEFAULT_VERSION, subVersionV5: SubVersionV5 = DEFAULT_V5_VERSION): ExtrinsicPayloadVx {
function decodeExtrinsicPayload (registry: Registry, value?: GenericExtrinsicPayload | ExtrinsicPayloadValue | Uint8Array | string, version: number = DEFAULT_VERSION, preamble: Preamble = DEFAULT_PREAMBLE): ExtrinsicPayloadVx {
if (value instanceof GenericExtrinsicPayload) {
return value.unwrap();
}

const extVersion = version === 5 ? V5_VERSIONS[subVersionV5] : VERSIONS[version] || VERSIONS[0];
const extVersion = version === 5 ? PREAMBLES[preamble] : VERSIONS[version] || VERSIONS[0];

/**
* HACK: In order to change the assetId from `number | object` to HexString (While maintaining the true type ie Option<TAssetConversion>),
Expand Down Expand Up @@ -76,8 +76,8 @@ function decodeExtrinsicPayload (registry: Registry, value?: GenericExtrinsicPay
* on the contents included
*/
export class GenericExtrinsicPayload extends AbstractBase<ExtrinsicPayloadVx> {
constructor (registry: Registry, value?: Partial<ExtrinsicPayloadValue> | Uint8Array | string, { subVersionV5, version }: ExtrinsicPayloadOptions = {}) {
super(registry, decodeExtrinsicPayload(registry, value as ExtrinsicPayloadValue, version, subVersionV5));
constructor (registry: Registry, value?: Partial<ExtrinsicPayloadValue> | Uint8Array | string, { pramble, version }: ExtrinsicPayloadOptions = {}) {
super(registry, decodeExtrinsicPayload(registry, value as ExtrinsicPayloadValue, version, pramble));
}

/**
Expand Down
14 changes: 13 additions & 1 deletion packages/types/src/extrinsic/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,19 @@ export const IMMORTAL_ERA = new Uint8Array([0]);

export const UNMASK_VERSION = 0b01111111;

export const DEFAULT_V5_VERSION = 'signed';
export const DEFAULT_PREAMBLE = 'signed';

// Latest extrinsic version is v5, which has backwards compatibility for v4 signed extrinsics
export const LATEST_EXTRINSIC_VERSION = 5;

export const VERSION_MASK = 0b00111111;

export const TYPE_MASK = 0b11000000;

export const BARE_EXTRINSIC = 0b00000000;

export const SIGNED_EXTRINSIC = 0b10000000;

export const GENERAL_EXTRINSIC = 0b01000000;

export const LOWEST_SUPPORTED_EXTRINSIC_FORMAT_VERSION = 4;

Check failure on line 31 in packages/types/src/extrinsic/constants.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

Newline required at end of file but not found
2 changes: 1 addition & 1 deletion packages/types/src/extrinsic/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ export interface ExtrinsicExtraValue {
tip?: AnyNumber;
}

export type SubVersionV5 = 'signed' | 'bare' | 'general';
export type Preamble = 'signed' | 'bare' | 'general';
7 changes: 7 additions & 0 deletions packages/types/src/extrinsic/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ export function sign (registry: Registry, signerPair: IKeyringPair, u8a: Uint8Ar

return signerPair.sign(encoded, options);
}

// a helper function for both types of payloads, Raw and metadata-known
export function signV5 (registry: Registry, signerPair: IKeyringPair, u8a: Uint8Array, options?: SignOptions): Uint8Array {
const encoded = registry.hash(u8a)

Check failure on line 19 in packages/types/src/extrinsic/util.ts

View workflow job for this annotation

GitHub Actions / pr (lint)

Missing semicolon

return signerPair.sign(encoded, options);
}
6 changes: 5 additions & 1 deletion packages/types/src/extrinsic/v5/Extrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { HexString } from '@polkadot/util/types';
import type { ExtrinsicSignatureV5 } from '../../interfaces/extrinsics/index.js';
import type { Address, Call } from '../../interfaces/runtime/index.js';
import type { ExtrinsicPayloadValue, IExtrinsicV5Impl, IKeyringPair, Registry, SignatureOptions } from '../../types/index.js';
import type { ExtrinsicOptions } from '../types.js';
import type { ExtrinsicOptions, Preamble } from '../types.js';

import { Struct } from '@polkadot/types-codec';
import { isU8a } from '@polkadot/util';
Expand Down Expand Up @@ -79,6 +79,10 @@ export class GenericExtrinsicV5 extends Struct implements IExtrinsicV5Impl {
return EXTRINSIC_VERSION;
}

public get preamble (): Preamble {
return this.getT('preamble');
}

/**
* @description Add an [[ExtrinsicSignatureV5]] to the extrinsic (already generated)
*/
Expand Down
3 changes: 2 additions & 1 deletion packages/types/src/extrinsic/v5/ExtrinsicPayload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { ExtrinsicPayloadValue, IKeyringPair } from '../../types/index.js';
import { Enum } from '@polkadot/types-codec';

import { GenericExtrinsicPayloadV4 } from '../v4/ExtrinsicPayload.js';
import { signV5 } from '../util.js';

/**
* @name GenericExtrinsicPayloadV5
Expand Down Expand Up @@ -39,6 +40,6 @@ export class GenericExtrinsicPayloadV5 extends GenericExtrinsicPayloadV4 {
// means that the data-as-signed is un-decodable, but is also doesn't need
// the extra information, only the pure data (and is not decoded) ...
// The same applies to V1..V3, if we have a V6, carry this comment
return signerPair.sign(this.registry.hash(this.toU8a({ method: true })), this.#signOptions);
return signV5(this.registry, signerPair, this.toU8a({ method: true }), this.#signOptions);
}
}

0 comments on commit b4a2f0f

Please sign in to comment.