Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# 0.82.0-beta.x

- **Breaking change** The `ContractsAbi` type has been moved from `@polkadot/types` to `import { Abi } from '@polkadot/api-contract`. This paves the way for an enhanced contracts interface, instead of dealing with low-level API calls.
- **Breaking change** `usize` is now a blacklisted type that will throw on construction. Since it is platform-specific, it creates incompatibilities between native (generally u64) and WASM (always u32) code. Use one of the `u32` or `u64` types explicitly.
- **Breaking change** `api.derive.contract` is now `api.derive.contracts` to align with the substrate 2.x rename. (Feture detection is used so it supports both 1.x and 2.x chains)
- **Breaking change** The api now uses the module name instead of the prefix to generate the storage methods. The methods of the grandpa module changed from `api.query.grandpaFinality` to `api.query.grandpa`.
- Update with latest substrate 2.x types
- **Breaking Change** StorageFunction has been renamed to StorageEntry.
- **Breaking Change** `@polkadot/extrinsics` and `@polkadot/storage` have been moved to `@polkadot/api-metadata` and are now accessible as `@polkadot/api-metadata/extrinsics` and `@polkadot/api-metadata/storage`, respectively.
- **Breaking Change** Vote interface extends U8a instead of I8. Vote properties can be accessed via the `isAye`, `isNay`, and `conviction` getters. Votes can still be constructed as before with a raw JS boolean, a SCALE encoded Boolean, an i8 number, or a JS object with properties `aye` and `conviction` defined.
- Support latest substrate 2.x v6 metadata with module constants using `api.consts`.
- Support V2 Extrinsics in addition to V1
- Addition of `api.derive.elections`
- `usize` is now a blacklisted type that will throw on construction. Since it is platform-specific, it creates incompatibilities between native (generally u64) and WASM (always u32) code. Use one of the `u32` or `u64` types explicitly.

# 0.81.1

Expand Down
18 changes: 1 addition & 17 deletions packages/api-metadata/src/extrinsics/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,6 @@ import extrinsics from './static';
const keyring = testingPairs({ type: 'ed25519' }, false);

describe('extrinsics', (): void => {
it('encodes extrinsic correctly (nobody)', (): void => {
Copy link
Member Author

@jacogr jacogr Jul 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I whacked this, technically a backwards incompatible change, however we have not had the nobody account in the system since poc-2 - so actually the test is bullsh*t. (inherents are now just unsigned, not with a nobody sig)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just remove it, then? Are we still supporting POC-2?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is why the test was removed. (It relied on an unsupported all-0 sig)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry, right, monday morning comment...

expect(
new Extrinsic(
extrinsics.timestamp.set(10101)
).sign(
keyring.nobody,
{
blockHash: new Uint8Array(),
nonce: 1234
}
).toU8a(true)
).toEqual(new Uint8Array([
129, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 19, 0, 2, 0, 213, 157
]));
});

it('encodes an actual transfer (actual data)', (): void => {
expect(
new Extrinsic(
Expand All @@ -41,7 +25,7 @@ describe('extrinsics', (): void => {
'ffd172a74cda4c865912c32ba0a80a57ae69abae410e5ccb59dee84e2f4432db4f' + // who
'fa4c192f6960a3bcdbdee5bcd9c26a3f971b131081912abcc31eab6a0b7589ab' + // sig1
'7f99b81a01738cb5e2a911a19d5daa5c0b654d4b8dbc521a6b29090c6d205903' + // sig2
'0000' + // nonce
'0000' + // nonce & era
'0500' + // balances.transfer
'ffd7568e5f0a7eda67a82691ff379ac4bba4f9c9b859fe779b5d46363b61ad2db9' + // to
'e56c' // value
Expand Down
34 changes: 27 additions & 7 deletions packages/api/src/Base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import { Storage } from '@polkadot/api-metadata/storage/types';
import storageFromMeta from '@polkadot/api-metadata/storage/fromMetadata';
import RpcCore from '@polkadot/rpc-core';
import { WsProvider } from '@polkadot/rpc-provider';
import { Event, getTypeRegistry, Hash, Metadata, Method, RuntimeVersion, Null, U64 } from '@polkadot/types';
import { Event, getTypeRegistry, Hash, Metadata, Method, RuntimeVersion, SignedBlock, Null, U64 } from '@polkadot/types';
import Linkage, { LinkageResult } from '@polkadot/types/codec/Linkage';
import { DEFAULT_VERSION as EXTRINSIC_DEFAULT_VERSION } from '@polkadot/types/primitive/Extrinsic/constants';
import { MethodFunction, ModulesWithMethods } from '@polkadot/types/primitive/Method';
import * as srmlTypes from '@polkadot/types/srml/definitions';
import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
Expand Down Expand Up @@ -72,6 +73,8 @@ export default abstract class ApiBase<ApiType> {

private _extrinsics?: SubmittableExtrinsics<ApiType>;

private _extrinsicVersion: number = EXTRINSIC_DEFAULT_VERSION;

private _genesisHash?: Hash;

protected _isConnected: BehaviorSubject<boolean>;
Expand Down Expand Up @@ -150,6 +153,13 @@ export default abstract class ApiBase<ApiType> {
this.init();
}

/**
* @description Returns th version of extrinsics in-use on this chain
*/
public get extrinsicVersion (): number {
return this._extrinsicVersion;
}

/**
* @description Contains the genesis Hash of the attached chain. Apart from being useful to determine the actual chain, it can also be used to sign immortal transactions.
*/
Expand Down Expand Up @@ -498,7 +508,9 @@ export default abstract class ApiBase<ApiType> {
this._rpcCore.chain.getBlockHash(0).toPromise(),
this._rpcCore.chain.getRuntimeVersion().toPromise()
]);

const metadataKey = `${this._genesisHash}-${(this._runtimeVersion as RuntimeVersion).specVersion}`;

if (metadataKey in metadata) {
this._runtimeMetadata = new Metadata(metadata[metadataKey]);
} else {
Expand All @@ -508,6 +520,7 @@ export default abstract class ApiBase<ApiType> {
// get unique types & validate
this.runtimeMetadata.getUniqTypes(false);
} else {
this._extrinsicVersion = this._options.source.extrinsicVersion;
this._runtimeMetadata = this._options.source.runtimeMetadata;
this._runtimeVersion = this._options.source.runtimeVersion;
this._genesisHash = this._options.source.genesisHash;
Expand All @@ -517,22 +530,29 @@ export default abstract class ApiBase<ApiType> {
const storage = storageFromMeta(this.runtimeMetadata);
const constants = constantsFromMeta(this.runtimeMetadata);

// only inject if we are not a clone (global init)
if (!this._options.source) {
Event.injectMetadata(this.runtimeMetadata);
Method.injectMethods(extrinsics);

// detect the extrinsic version in-use based on the last block
const lastBlock: SignedBlock = await this._rpcCore.chain.getBlock().toPromise();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now determine the extrinsic version from the chain - basically, based on the last block, we pull out the version from contained extrinsics and then use this in any future construction of this type.


this._extrinsicVersion = lastBlock.block.extrinsics[0].versionFormat;
}

this._extrinsics = this.decorateExtrinsics(extrinsics, this.decorateMethod);
this._query = this.decorateStorage(storage, this.decorateMethod);
this._consts = constants;

this._rx.extrinsicVersion = this._extrinsicVersion;
this._rx.genesisHash = this._genesisHash;
this._rx.runtimeVersion = this._runtimeVersion;
this._rx.tx = this.decorateExtrinsics(extrinsics, rxDecorateMethod);
this._rx.query = this.decorateStorage(storage, rxDecorateMethod);
this._rx.consts = constants;
this._derive = this.decorateDerive(this._rx as ApiInterfaceRx, this.decorateMethod);

// only inject if we are not a clone (global init)
if (!this._options.source) {
Event.injectMetadata(this.runtimeMetadata);
Method.injectMethods(extrinsics);
}
this._derive = this.decorateDerive(this._rx as ApiInterfaceRx, this.decorateMethod);

return true;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/api/src/SubmittableExtrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export default function createSubmittableExtrinsic<ApiType> (
extrinsic: Method | Uint8Array | string,
trackingCb?: Callback<ISubmittableResult>
): SubmittableExtrinsic<ApiType> {
const _extrinsic = new (getTypeRegistry().getOrThrow('Extrinsic'))(extrinsic) as SubmittableExtrinsic<ApiType>;
const _extrinsic = new (getTypeRegistry().getOrThrow('Extrinsic'))(extrinsic, api.extrinsicVersion) as SubmittableExtrinsic<ApiType>;
const _noStatusCb = type === 'rxjs';

function updateSigner (updateId: number, status: Hash | ISubmittableResult): void {
Expand Down Expand Up @@ -263,6 +263,7 @@ export default function createSubmittableExtrinsic<ApiType> (
updateId = await api.signer.sign(_extrinsic, address, {
...eraOptions,
blockNumber: header ? header.blockNumber : new BN(0),
extrinsicVersion: this.api.extrinsicVersion,
genesisHash: api.genesisHash
});
} else {
Expand Down
2 changes: 2 additions & 0 deletions packages/api/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ export interface ApiOptions {
// A smaller interface of ApiRx, used in derive and in SubmittableExtrinsic
export interface ApiInterfaceRx {
consts: Constants;
extrinsicVersion: number;
genesisHash: Hash;
hasSubscriptions: boolean;
runtimeMetadata: Metadata;
Expand All @@ -225,6 +226,7 @@ export type ApiTypes = 'promise' | 'rxjs';

export interface SignerOptions extends SignatureOptions {
blockNumber: BN;
extrinsicVersion: number;
genesisHash: Hash;
}

Expand Down
10 changes: 5 additions & 5 deletions packages/types/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ These primitive types are available:
| [[Data]] | A raw data structure. It is an encoding of a U8a without any length encoding |
| [[Event]] | Wrapper for the actual data that forms part of an [[Event]] |
| [[EventRecord]] | A record for an [[Event]] (as specified by [[Metadata]]) with the specific [[Phase]] of application |
| [[Extrinsic]] | Representation of an Extrinsic in the system |
| [[ExtrinsicEra]] | The era for an extrinsic, indicating either a mortal or immortal extrinsic |
| [[ExtrinsicSignature]] | A container for the [[Signature]] associated with a specific [[Extrinsic]] |
| [[H160]] | Hash containing 160 bits (20 bytes), typically used in blocks, extrinsics and as a sane default |
| [[H256]] | Hash containing 256 bits (32 bytes), typically used in blocks, extrinsics and as a sane default |
| [[H512]] | Hash containing 512 bits (64 bytes), typically used for signatures |
Expand All @@ -57,6 +60,8 @@ These primitive types are available:
| [[Null]] | Implements a type that does not contain anything (apart from `null`) |
| [[Origin]] | Where Origin occurs, it should be ignored as an internal-only value |
| [[Signature]] | The default signature that is used accross the system |
| [[SignaturePayload]] | A signing payload for an [[Extrinsic]]. For the final encoding, it is variable length based on the contents included |
| [[SignaturePayloadRaw]] | A version of the [[SignaturePayload]] where it doesn't rely on [[Method]] with metadata, rather it treats the values as a raw byte stream |
| [[StorageData]] | Data retrieved via Storage queries and data for key-value pairs |
| [[StorageKey]] | A representation of a storage key (typically hashed) in the system |
| [[Text]] | This is a string wrapper, along with the length. |
Expand Down Expand Up @@ -97,10 +102,7 @@ These custom types implement specific types that are found as part of the Substr
| [[ContractStorageKey]] | A representation of a storage key for contracts |
| [[EraIndex]] | A representation for the era count |
| [[Exposure]] | A snapshot of the stake backing a single validator in the system |
| [[Extrinsic]] | Representation of an Extrinsic in the system |
| [[ExtrinsicEra]] | The era for an extrinsic, indicating either a mortal or immortal extrinsic |
| [[Extrinsics]] | A [[Vector]] of [[Extrinsic]] |
| [[ExtrinsicSignature]] | A container for the [[Signature]] associated with a specific [[Extrinsic]] |
| [[Gas]] | A gas number type for Substrate, extending [[U64]] |
| [[IndividualExposure]] | The Substrate IndividualExposure for staking |
| [[InherentOfflineReport]] | Describes the offline-reporting extrinsic |
Expand Down Expand Up @@ -135,8 +137,6 @@ These custom types implement specific types that are found as part of the Substr
| [[SessionKey]] | Wrapper for a SessionKey. Same as an normal [[AuthorityId]], i.e. a wrapper around publicKey |
| [[SessionKeys]] | Wrapper for the session and authority ids |
| [[SetIndex]] | Set index, implemented as a [[U32]] |
| [[SignaturePayload]] | A signing payload for an [[Extrinsic]]. For the final encoding, it is variable length based on the contents included |
| [[SignaturePayloadRaw]] | A version of the [[SignaturePayload]] where it doesn't rely on [[Method]] with metadata, rather it treats the values as a raw byte stream |
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw variant disappeared. The normal payload is now the same as the raw variant. We cannot continue to add special cases - this has a very limited impact, since it is just signers that actually use it. (extensions & internally to sumittable)

| [[StakingLedger]] | The ledger of a (bonded) stash |
| [[StoredPendingChange]] | Stored pending change for a Grandpa events |
| [[TreasuryProposal]] | A Proposal made for Treasury |
Expand Down
61 changes: 60 additions & 1 deletion packages/types/src/codec/Base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,73 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { AnyJson, Codec } from '../types';

/**
* @name Base
* @description A type extends the Base class, when it holds a value
*/
export default class Base<T> {
export default abstract class Base<T extends Codec> implements Codec {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make extension less noisy, the base defaults have been included into Base. Anything that extends it have been adjusted to remove duplication. (This happened since I really didn't want to add more boilerplate to the new classes, so rather cleaned up all)

protected raw: T;

public constructor (value?: any) {
this.raw = value;
}

/**
* @description The length of the value when encoded as a Uint8Array
*/
public get encodedLength (): number {
return this.toU8a().length;
}

/**
* @description Checks if the value is an empty value
*/
public get isEmpty (): boolean {
return this.raw.isEmpty;
}

/**
* @description Compares the value of the input to see if there is a match
*/
public eq (other?: any): boolean {
return this.raw.eq(other);
}

/**
* @description Returns a hex string representation of the value. isLe returns a LE (number-only) representation
*/
public toHex (isLe?: boolean): string {
return this.raw.toHex(isLe);
}

/**
* @description Converts the Object to JSON, typically used for RPC transfers
*/
public toJSON (): AnyJson {
return this.raw.toJSON();
}

/**
* @description Returns the string representation of the value
*/
public toString (): string {
return this.raw.toString();
}

/**
* @description Encodes the value as a Uint8Array as per the SCALE specifications
* @param isBare true when the value has none of the type-specific prefixes (internal)
*/
public toU8a (isBare?: boolean): Uint8Array {
return this.raw.toU8a(isBare);
}

/**
* @description Returns the base runtime type name for this instance
*/
public toRawType (): string {
return 'Base';
}
}
39 changes: 2 additions & 37 deletions packages/types/src/codec/Compact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { bnToBn, compactAddLength, compactFromU8a, compactStripLength, compactTo
import { DEFAULT_BITLENGTH } from '@polkadot/util/compact/defaults';

import Moment from '../primitive/Moment';
import { AnyNumber, Codec, Constructor } from '../types';
import { AnyNumber, Constructor } from '../types';
import { UIntBitLength } from './AbstractInt';
import Base from './Base';
import UInt from './UInt';
Expand All @@ -20,7 +20,7 @@ import UInt from './UInt';
* used by other types to add length-prefixed encoding, or in the case of wrapped types, taking
* a number and making the compact representation thereof
*/
export default class Compact extends Base<UInt | Moment> implements Codec {
export default class Compact extends Base<UInt | Moment> {
public constructor (Type: Constructor<UInt | Moment>, value: Compact | AnyNumber = 0) {
super(Compact.decodeCompact(Type, value));
}
Expand Down Expand Up @@ -68,20 +68,6 @@ export default class Compact extends Base<UInt | Moment> implements Codec {
return new Type(_value);
}

/**
* @description The length of the value when encoded as a Uint8Array
*/
public get encodedLength (): number {
return this.toU8a().length;
}

/**
* @description Checks if the value is an empty value
*/
public get isEmpty (): boolean {
return this.raw.isEmpty;
}

/**
* @description Returns the number of bits in the value
*/
Expand All @@ -107,20 +93,6 @@ export default class Compact extends Base<UInt | Moment> implements Codec {
return this.raw.toBn();
}

/**
* @description Returns a hex string representation of the value
*/
public toHex (isLe?: boolean): any {
return this.raw.toHex(isLe);
}

/**
* @description Converts the Object to JSON, typically used for RPC transfers
*/
public toJSON (): string | number {
return this.raw.toJSON();
}

/**
* @description Returns the number representation for the value
*/
Expand All @@ -135,13 +107,6 @@ export default class Compact extends Base<UInt | Moment> implements Codec {
return `Compact<${this.raw.toRawType()}>`;
}

/**
* @description Returns the string representation of the value
*/
public toString (): string {
return this.raw.toString();
}

/**
* @description Encodes the value as a Uint8Array as per the SCALE specifications
* @param isBare true when the value has none of the type-specific prefixes (internal)
Expand Down
9 changes: 1 addition & 8 deletions packages/types/src/codec/EnumType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ interface Decoded {
// TODO:
// - As per Enum, actually use TS enum
// - It should rather probably extend Enum instead of copying code
export default class Enum extends Base<Codec> implements Codec {
export default class Enum extends Base<Codec> {
private _def: TypesDef;

private _index: number;
Expand Down Expand Up @@ -172,13 +172,6 @@ export default class Enum extends Base<Codec> implements Codec {
return this._index;
}

/**
* @description Checks if the value is an empty value
*/
public get isEmpty (): boolean {
return this.isEmpty;
}

/**
* @description Checks if the Enum points to a [[Null]] type
*/
Expand Down
Loading