Make v4 payload driven by extension fields (#4017)

* Make v4 payload driven by extension fields

* Add getters for additional fields

* Move keys

* Re-adjust

* abstract

* SignerPayload fields

* CHANGELOG
This commit is contained in:
Jaco
2021-11-06 22:42:14 +02:00
committed by GitHub
parent 442dba42ba
commit ca755d3e0d
4 changed files with 50 additions and 25 deletions
+1
View File
@@ -11,6 +11,7 @@ Changelog:
Changes: Changes:
- Dynamically inject getters for Extrinsic payloads
- Optimize caching for previously constructed type classes per registry - Optimize caching for previously constructed type classes per registry
- Convert metadata, rpc and api to use lazy decoration - Convert metadata, rpc and api to use lazy decoration
- Split u8a decoding paths for Vec (different from general path) - Split u8a decoding paths for Vec (different from general path)
+15
View File
@@ -13,6 +13,7 @@ import type { ExtrinsicValueV4 } from './v4/Extrinsic';
import { assert, compactAddLength, compactFromU8a, isHex, isU8a, objectSpread, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util'; import { assert, compactAddLength, compactFromU8a, isHex, isU8a, objectSpread, u8aConcat, u8aToHex, u8aToU8a } from '@polkadot/util';
import { Base } from '../codec/Base'; import { Base } from '../codec/Base';
import { defineProperty } from '../codec/utils';
import { BIT_SIGNED, BIT_UNSIGNED, DEFAULT_VERSION, UNMASK_VERSION } from './constants'; import { BIT_SIGNED, BIT_UNSIGNED, DEFAULT_VERSION, UNMASK_VERSION } from './constants';
interface CreateOptions { interface CreateOptions {
@@ -36,6 +37,20 @@ const VERSIONS = [
export { EXTRINSIC_VERSION as LATEST_EXTRINSIC_VERSION } from './v4/Extrinsic'; export { EXTRINSIC_VERSION as LATEST_EXTRINSIC_VERSION } from './v4/Extrinsic';
abstract class ExtrinsicBase<A extends AnyTuple> extends Base<ExtrinsicVx | ExtrinsicUnknown> { abstract class ExtrinsicBase<A extends AnyTuple> extends Base<ExtrinsicVx | ExtrinsicUnknown> {
constructor (registry: Registry, value: ExtrinsicV4 | ExtrinsicUnknown, initialU8aLength?: number) {
super(registry, value, initialU8aLength);
const signKeys = Object.keys(registry.getSignedExtensionTypes());
// This is on the abstract class, ensuring that hasOwnProperty operates
// correctly, i.e. it needs to be on the base class exposing it
for (let i = 0; i < signKeys.length; i++) {
const key = signKeys[i];
defineProperty(this, key, () => (this._raw as ExtrinsicVx).signature[key as 'signer']);
}
}
/** /**
* @description The arguments passed to for the call, exposes args so it is compatible with [[Call]] * @description The arguments passed to for the call, exposes args so it is compatible with [[Call]]
*/ */
@@ -10,6 +10,7 @@ import { objectSpread, u8aToHex } from '@polkadot/util';
import { Compact } from '../codec/Compact'; import { Compact } from '../codec/Compact';
import { Option } from '../codec/Option'; import { Option } from '../codec/Option';
import { Struct } from '../codec/Struct'; import { Struct } from '../codec/Struct';
import { defineProperty } from '../codec/utils';
import { Vec } from '../codec/Vec'; import { Vec } from '../codec/Vec';
import { Text } from '../primitive/Text'; import { Text } from '../primitive/Text';
import { u8 } from '../primitive/U8'; import { u8 } from '../primitive/U8';
@@ -62,6 +63,8 @@ export class GenericSignerPayload extends Struct implements ISignerPayload, Sign
if (!knownTypes[key]) { if (!knownTypes[key]) {
this._extraTypes[key] = type; this._extraTypes[key] = type;
} }
defineProperty(this, key, () => this.get(key));
} }
} }
@@ -3,16 +3,16 @@
import type { HexString } from '@polkadot/util/types'; import type { HexString } from '@polkadot/util/types';
import type { EcdsaSignature, Ed25519Signature, ExtrinsicEra, ExtrinsicSignature, Sr25519Signature } from '../../interfaces/extrinsics'; import type { EcdsaSignature, Ed25519Signature, ExtrinsicEra, ExtrinsicSignature, Sr25519Signature } from '../../interfaces/extrinsics';
import type { Address, AssetId, Balance, Call, Index } from '../../interfaces/runtime'; import type { Address, Balance, Call, Index } from '../../interfaces/runtime';
import type { ExtrinsicPayloadValue, IExtrinsicSignature, IKeyringPair, Registry, SignatureOptions } from '../../types'; import type { ExtrinsicPayloadValue, IExtrinsicSignature, IKeyringPair, Registry, SignatureOptions } from '../../types';
import type { ExtrinsicSignatureOptions } from '../types'; import type { ExtrinsicSignatureOptions } from '../types';
import { assert, isU8a, objectSpread, stringify, u8aConcat, u8aToHex } from '@polkadot/util'; import { assert, isU8a, isUndefined, objectSpread, stringify, u8aConcat, u8aToHex } from '@polkadot/util';
import { Compact } from '../../codec/Compact'; import { Compact } from '../../codec/Compact';
import { Enum } from '../../codec/Enum'; import { Enum } from '../../codec/Enum';
import { Option } from '../../codec/Option';
import { Struct } from '../../codec/Struct'; import { Struct } from '../../codec/Struct';
import { defineProperty } from '../../codec/utils';
import { EMPTY_U8A, IMMORTAL_ERA } from '../constants'; import { EMPTY_U8A, IMMORTAL_ERA } from '../constants';
import { GenericExtrinsicPayloadV4 } from './ExtrinsicPayload'; import { GenericExtrinsicPayloadV4 } from './ExtrinsicPayload';
@@ -30,14 +30,17 @@ function toAddress (registry: Registry, address: Address | Uint8Array | string):
*/ */
export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSignature { export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSignature {
#fakePrefix: Uint8Array; #fakePrefix: Uint8Array;
#signKeys: string[];
constructor (registry: Registry, value?: GenericExtrinsicSignatureV4 | Uint8Array, { isSigned }: ExtrinsicSignatureOptions = {}) { constructor (registry: Registry, value?: GenericExtrinsicSignatureV4 | Uint8Array, { isSigned }: ExtrinsicSignatureOptions = {}) {
const signTypes = registry.getSignedExtensionTypes();
super( super(
registry, registry,
objectSpread( objectSpread(
// eslint-disable-next-line sort-keys // eslint-disable-next-line sort-keys
{ signer: 'Address', signature: 'ExtrinsicSignature' }, { signer: 'Address', signature: 'ExtrinsicSignature' },
registry.getSignedExtensionTypes() signTypes
), ),
GenericExtrinsicSignatureV4.decodeExtrinsicSignature(value, isSigned) GenericExtrinsicSignatureV4.decodeExtrinsicSignature(value, isSigned)
); );
@@ -45,6 +48,13 @@ export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSig
this.#fakePrefix = registry.createType('ExtrinsicSignature') instanceof Enum this.#fakePrefix = registry.createType('ExtrinsicSignature') instanceof Enum
? FAKE_SOME ? FAKE_SOME
: FAKE_NONE; : FAKE_NONE;
this.#signKeys = Object.keys(signTypes);
for (let i = 0; i < this.#signKeys.length; i++) {
const key = this.#signKeys[i];
defineProperty(this, key, () => this.get(key));
}
} }
/** @internal */ /** @internal */
@@ -119,21 +129,20 @@ export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSig
return this.get('tip') as Compact<Balance>; return this.get('tip') as Compact<Balance>;
} }
/** protected _injectSignature (signer: Address, signature: ExtrinsicSignature, payload: GenericExtrinsicPayloadV4): IExtrinsicSignature {
* @description // use the fields exposed to guide the getters
* The (optional) asset id for this signature for chains that support transaction fees in assets for (let i = 0; i < this.#signKeys.length; i++) {
*/ const k = this.#signKeys[i];
public get assetId (): Option<AssetId> { const v = payload.get(k);
return this.get('assetId') as Option<AssetId>;
}
protected _injectSignature (signer: Address, signature: ExtrinsicSignature, { assetId, era, nonce, tip }: GenericExtrinsicPayloadV4): IExtrinsicSignature { if (!isUndefined(v)) {
this.set('era', era); this.set(k, v);
this.set('nonce', nonce); }
}
// additional fields (exposed in struct itself)
this.set('signer', signer); this.set('signer', signer);
this.set('signature', signature); this.set('signature', signature);
this.set('tip', tip);
this.set('assetId', assetId);
return this; return this;
} }
@@ -152,18 +161,15 @@ export class GenericExtrinsicSignatureV4 extends Struct implements IExtrinsicSig
/** /**
* @description Creates a payload from the supplied options * @description Creates a payload from the supplied options
*/ */
public createPayload (method: Call, { assetId, blockHash, era, genesisHash, nonce, runtimeVersion: { specVersion, transactionVersion }, tip }: SignatureOptions): GenericExtrinsicPayloadV4 { public createPayload (method: Call, options: SignatureOptions): GenericExtrinsicPayloadV4 {
return new GenericExtrinsicPayloadV4(this.registry, { const { era, runtimeVersion: { specVersion, transactionVersion } } = options;
assetId,
blockHash, return new GenericExtrinsicPayloadV4(this.registry, objectSpread<ExtrinsicPayloadValue>({}, options, {
era: era || IMMORTAL_ERA, era: era || IMMORTAL_ERA,
genesisHash,
method: method.toHex(), method: method.toHex(),
nonce,
specVersion, specVersion,
tip: tip || 0, transactionVersion
transactionVersion: transactionVersion || 0 }));
});
} }
/** /**