From 895ed8044976633166babc134e5d7189621d62eb Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 24 Aug 2019 12:10:42 +0200 Subject: [PATCH] subscribeNewHeads (#1338) * subscribeNewHeads * Update CHANGELOG * Rebuild interfaces * Sort interfaces, really expose plural * Fix mocks --- CHANGELOG.md | 1 + packages/api-derive/src/chain/bestNumber.ts | 2 +- packages/api-derive/src/chain/getHeader.ts | 2 +- packages/api-derive/src/chain/index.ts | 2 +- .../{subscribeNewHead.ts => subscribeNewHeads.ts} | 8 ++++---- packages/api/README.md | 4 ++-- packages/api/src/base/Decorate.ts | 2 +- packages/api/src/base/index.ts | 4 ++-- packages/api/src/checkTypes.manual.ts | 4 ++-- packages/api/src/promise/Api.ts | 6 +++--- packages/api/src/rx/Api.ts | 6 +++--- packages/api/test/e2e/api-derive/promise.spec.ts | 2 +- packages/api/test/e2e/api-derive/rx.spec.ts | 4 ++-- packages/api/test/e2e/api/promise-queries.spec.ts | 4 ++-- packages/api/test/e2e/api/promise-tx-eras.spec.ts | 4 ++-- packages/api/test/e2e/rpc-core/chain.spec.ts | 4 ++-- packages/rpc-core/README.md | 2 +- packages/rpc-core/src/cached.spec.ts | 12 ++++++------ packages/rpc-core/src/jsonrpc.types.ts | 6 +++--- packages/rpc-core/src/replay.spec.ts | 2 +- packages/rpc-provider/src/mock/index.ts | 1 + packages/type-jsonrpc/src/chain.ts | 5 +++-- packages/types/src/scripts/interfacesTs.ts | 6 ++++-- 23 files changed, 49 insertions(+), 44 deletions(-) rename packages/api-derive/src/chain/{subscribeNewHead.ts => subscribeNewHeads.ts} (87%) diff --git a/CHANGELOG.md b/CHANGELOG.md index af941b9250..12b220b166 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with the [migration guide](UPGRADING.md). +- **Breaking change** `api.rpc.chain.subscribeNewHeads` is now available as opposed to the old `subscribeNewHead`. This aligns with the Substrate implementation. - **Breaking change** Substrate 2.x & Polkadot master has moved both `BlockNumber` & `Index` to `u32`. The API tracks these closely. If you are running a chain with `u64` values (for either), pass the type override to the API on creation, e.g. `ApiPromise.create({ types: { BlockNumber: 'u64', Index: 'u64' } })` to avoid getting warnings about mismatched types. - **Breaking change** `Api.create(...)` and `new Api(...)` now only takes an options Object, so if you passed the provider directly previously, you need to swap the use to `Api.create({ provider: ... })` - **Breaking change** Runtime types have been extended and moved to definitions instead of classes diff --git a/packages/api-derive/src/chain/bestNumber.ts b/packages/api-derive/src/chain/bestNumber.ts index 4fce9e1851..0d3d465bc2 100644 --- a/packages/api-derive/src/chain/bestNumber.ts +++ b/packages/api-derive/src/chain/bestNumber.ts @@ -24,7 +24,7 @@ import { drr } from '../util/drr'; */ export function bestNumber (api: ApiInterfaceRx): () => Observable { return (): Observable => - api.rpc.chain.subscribeNewHead().pipe( + api.rpc.chain.subscribeNewHeads().pipe( map((header): BlockNumber => header.number.unwrap()), drr() ); diff --git a/packages/api-derive/src/chain/getHeader.ts b/packages/api-derive/src/chain/getHeader.ts index 67bde7eb65..09eac3f989 100644 --- a/packages/api-derive/src/chain/getHeader.ts +++ b/packages/api-derive/src/chain/getHeader.ts @@ -8,7 +8,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { HeaderExtended } from '../type'; import { drr } from '../util/drr'; -import { HeaderAndValidators } from './subscribeNewHead'; +import { HeaderAndValidators } from './subscribeNewHeads'; /** * @name bestNumberFinalized diff --git a/packages/api-derive/src/chain/index.ts b/packages/api-derive/src/chain/index.ts index ddfc17ebb5..fe329ced7c 100644 --- a/packages/api-derive/src/chain/index.ts +++ b/packages/api-derive/src/chain/index.ts @@ -6,4 +6,4 @@ export * from './bestNumber'; export * from './bestNumberFinalized'; export * from './bestNumberLag'; export * from './getHeader'; -export * from './subscribeNewHead'; +export * from './subscribeNewHeads'; diff --git a/packages/api-derive/src/chain/subscribeNewHead.ts b/packages/api-derive/src/chain/subscribeNewHeads.ts similarity index 87% rename from packages/api-derive/src/chain/subscribeNewHead.ts rename to packages/api-derive/src/chain/subscribeNewHeads.ts index b7b273b614..6207639fe1 100644 --- a/packages/api-derive/src/chain/subscribeNewHead.ts +++ b/packages/api-derive/src/chain/subscribeNewHeads.ts @@ -14,21 +14,21 @@ import { drr } from '../util/drr'; export type HeaderAndValidators = [Header, AccountId[]]; /** - * @name subscribeNewHead + * @name subscribeNewHeads * @returns An array containing the block header and the block author * @description An observable of the current block header and it's author * @example *
* * ```javascript - * api.derive.chain.subscribeNewHead(({ author, blockNumber }) => { + * api.derive.chain.subscribeNewHeads(({ author, blockNumber }) => { * console.log(`block #${blockNumber} was authored by ${author}`); * }); * ``` */ -export function subscribeNewHead (api: ApiInterfaceRx): () => Observable { +export function subscribeNewHeads (api: ApiInterfaceRx): () => Observable { return (): Observable => - api.rpc.chain.subscribeNewHead().pipe( + api.rpc.chain.subscribeNewHeads().pipe( switchMap((header: Header): Observable => (combineLatest([ of(header), diff --git a/packages/api/README.md b/packages/api/README.md index 0718f9f481..7e89636ca4 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -45,7 +45,7 @@ import { ApiPromise } from '@polkadot/api'; const api = await ApiPromise.create(); // make a call to retrieve the current network head -api.rpc.chain.subscribeNewHead((header) => { +api.rpc.chain.subscribeNewHeads((header) => { console.log(`Chain is at #${header.blockNumber}`); }); ``` @@ -59,7 +59,7 @@ import { ApiRx } from '@polkadot/api'; const api = await ApiRx.create().toPromise(); // make a call to retrieve the current network head -api.rpc.chain.subscribeNewHead().subscribe((header) => { +api.rpc.chain.subscribeNewHeads().subscribe((header) => { console.log(`Chain is at #${header.blockNumber}`); }); ``` diff --git a/packages/api/src/base/Decorate.ts b/packages/api/src/base/Decorate.ts index 27c35bc178..af9d238b56 100644 --- a/packages/api/src/base/Decorate.ts +++ b/packages/api/src/base/Decorate.ts @@ -82,7 +82,7 @@ export default abstract class Decorate extends Events { * * const api = new Api().isReady(); * - * api.rpc.subscribeNewHead((header) => { + * api.rpc.subscribeNewHeads((header) => { * console.log(`new block #${header.number.toNumber()}`); * }); * ``` diff --git a/packages/api/src/base/index.ts b/packages/api/src/base/index.ts index a1a2071aa0..ea872f5b39 100644 --- a/packages/api/src/base/index.ts +++ b/packages/api/src/base/index.ts @@ -47,7 +47,7 @@ export default abstract class ApiBase extends Init { * * const api = new Api().isReady(); * - * api.rpc.subscribeNewHead((header) => { + * api.rpc.subscribeNewHeads((header) => { * console.log(`new block #${header.number.toNumber()}`); * }); * ``` @@ -169,7 +169,7 @@ export default abstract class ApiBase extends Init { *
* * ```javascript - * api.rpc.chain.subscribeNewHead((header) => { + * api.rpc.chain.subscribeNewHeads((header) => { * console.log('new header', header); * }); * ``` diff --git a/packages/api/src/checkTypes.manual.ts b/packages/api/src/checkTypes.manual.ts index 0c5c1f5549..a3d129c195 100644 --- a/packages/api/src/checkTypes.manual.ts +++ b/packages/api/src/checkTypes.manual.ts @@ -24,7 +24,7 @@ async function consts (api: ApiPromise): Promise { } async function derive (api: ApiPromise): Promise { - await api.derive.chain.subscribeNewHead((header: HeaderExtended): void => { + await api.derive.chain.subscribeNewHeads((header: HeaderExtended): void => { console.log('current author:', header.author); }); @@ -49,7 +49,7 @@ async function query (api: ApiPromise, keyring: TestKeyringMap): Promise { } async function rpc (api: ApiPromise): Promise { - await api.rpc.chain.subscribeNewHead((header: Header): void => { + await api.rpc.chain.subscribeNewHeads((header: Header): void => { console.log('current header:', header); }); diff --git a/packages/api/src/promise/Api.ts b/packages/api/src/promise/Api.ts index 2f021cb181..c48751860f 100644 --- a/packages/api/src/promise/Api.ts +++ b/packages/api/src/promise/Api.ts @@ -82,7 +82,7 @@ function promiseTracker (resolve: (value: () => void) => void, reject: (value: E * const api = await ApiPromise.create(); * * // make a subscription to the network head - * api.rpc.chain.subscribeNewHead((header) => { + * api.rpc.chain.subscribeNewHeads((header) => { * console.log(`Chain is at #${header.number}`); * }); * ``` @@ -176,7 +176,7 @@ export default class ApiPromise extends ApiBase<'promise'> { * import Api from '@polkadot/api/promise'; * * new Api().isReady.then((api) => { - * api.rpc.subscribeNewHead((header) => { + * api.rpc.subscribeNewHeads((header) => { * console.log(`new block #${header.number.toNumber()}`); * }); * }); @@ -221,7 +221,7 @@ export default class ApiPromise extends ApiBase<'promise'> { * * // combines values from balance & nonce as it updates * api.combineLatest([ - * api.rpc.chain.subscribeNewHead, + * api.rpc.chain.subscribeNewHeads, * [api.query.balances.freeBalance, address], * (cb) => api.query.system.accountNonce(address, cb) * ], ([head, balance, nonce]) => { diff --git a/packages/api/src/rx/Api.ts b/packages/api/src/rx/Api.ts index 6181c758fe..b91d6e818f 100644 --- a/packages/api/src/rx/Api.ts +++ b/packages/api/src/rx/Api.ts @@ -35,7 +35,7 @@ import ApiBase from '../base'; * const api = await ApiRx.create().toPromise(); * * // make a call to retrieve the current network head - * api.rpc.chain.subscribeNewHead().subscribe((header) => { + * api.rpc.chain.subscribeNewHeads().subscribe((header) => { * console.log(`Chain is at #${header.number}`); * }); * ``` @@ -125,7 +125,7 @@ export default class ApiRx extends ApiBase<'rxjs'> { * Api.create() * .pipe( * switchMap((api) => - * api.rpc.chain.subscribeNewHead() + * api.rpc.chain.subscribeNewHeads() * )) * .subscribe((header) => { * console.log(`new block #${header.number.toNumber()}`); @@ -149,7 +149,7 @@ export default class ApiRx extends ApiBase<'rxjs'> { * new Api().isReady * .pipe( * switchMap((api) => - * api.rpc.chain.subscribeNewHead() + * api.rpc.chain.subscribeNewHeads() * )) * .subscribe((header) => { * console.log(`new block #${header.number.toNumber()}`); diff --git a/packages/api/test/e2e/api-derive/promise.spec.ts b/packages/api/test/e2e/api-derive/promise.spec.ts index 245a2b0a6b..470d74d3c8 100644 --- a/packages/api/test/e2e/api-derive/promise.spec.ts +++ b/packages/api/test/e2e/api-derive/promise.spec.ts @@ -31,7 +31,7 @@ describeE2E()('Derive Promise e2e', (wsUrl: string): void => { }); it('subscribes to newHead, retrieving the actual validator', (done): Promise<() => void> => { - return api.derive.chain.subscribeNewHead(({ author }: HeaderExtended): void => { + return api.derive.chain.subscribeNewHeads(({ author }: HeaderExtended): void => { console.log('author', author && author.toString()); if (author) { diff --git a/packages/api/test/e2e/api-derive/rx.spec.ts b/packages/api/test/e2e/api-derive/rx.spec.ts index a9bfc417f7..1ca4c9f38a 100644 --- a/packages/api/test/e2e/api-derive/rx.spec.ts +++ b/packages/api/test/e2e/api-derive/rx.spec.ts @@ -199,10 +199,10 @@ describeE2E({ }); }); - describe('subscribeNewHead', (): void => { + describe('subscribeNewHeads', (): void => { it('gets an observable of the current block header and it\'s author', async (done): Promise => { // eslint-disable-next-line @typescript-eslint/no-unused-vars - api.derive.chain.subscribeNewHead().subscribe((headerExtended: HeaderExtended): void => { + api.derive.chain.subscribeNewHeads().subscribe((headerExtended: HeaderExtended): void => { // WIP https://github.com/polkadot-js/api/issues/868 done(); }); diff --git a/packages/api/test/e2e/api/promise-queries.spec.ts b/packages/api/test/e2e/api/promise-queries.spec.ts index 4b0e7a66ed..4acdd98b2a 100644 --- a/packages/api/test/e2e/api/promise-queries.spec.ts +++ b/packages/api/test/e2e/api/promise-queries.spec.ts @@ -33,7 +33,7 @@ describeE2E()('Promise e2e queries', (wsUrl: string): void => { it('subscribes to rpc', (done): Promise<() => void> => { return ( - api.rpc.chain.subscribeNewHead((header: Header): void => { + api.rpc.chain.subscribeNewHeads((header: Header): void => { expect(header.number.isEmpty).toBe(false); done(); @@ -53,7 +53,7 @@ describeE2E()('Promise e2e queries', (wsUrl: string): void => { it('subscribes to derive', (done): Promise<() => void> => { return ( - api.derive.chain.subscribeNewHead((header: HeaderExtended): void => { + api.derive.chain.subscribeNewHeads((header: HeaderExtended): void => { expect(header.number.isEmpty).toBe(false); done(); diff --git a/packages/api/test/e2e/api/promise-tx-eras.spec.ts b/packages/api/test/e2e/api/promise-tx-eras.spec.ts index 22c996b78d..527aa2ad7f 100644 --- a/packages/api/test/e2e/api/promise-tx-eras.spec.ts +++ b/packages/api/test/e2e/api/promise-tx-eras.spec.ts @@ -82,7 +82,7 @@ describeE2E({ const blockHash = signedBlock.block.header.hash; const ex = api.tx.balances.transfer(keyring.eve.address, 12345); - await api.rpc.chain.subscribeNewHead(async (header: Header): Promise => { + await api.rpc.chain.subscribeNewHeads(async (header: Header): Promise => { if (header.number.toNumber() === eraDeath - 1) { try { await ex.signAndSend(keyring.alice, { blockHash, era: exERA, nonce } as any); @@ -111,7 +111,7 @@ describeE2E({ const blockHash = signedBlock.block.header.hash; const ex = api.tx.balances.transfer(keyring.eve.address, 12121); - await api.rpc.chain.subscribeNewHead(async (header: Header): Promise => { + await api.rpc.chain.subscribeNewHeads(async (header: Header): Promise => { if (header.number.toNumber() === eraDeath - 1) { try { await ex.signAndSend(keyring.alice.address, { blockHash, era: exERA, nonce } as any); diff --git a/packages/api/test/e2e/rpc-core/chain.spec.ts b/packages/api/test/e2e/rpc-core/chain.spec.ts index 69128fac1d..a90ed9758c 100644 --- a/packages/api/test/e2e/rpc-core/chain.spec.ts +++ b/packages/api/test/e2e/rpc-core/chain.spec.ts @@ -23,11 +23,11 @@ describeE2E({ rpc = new Rpc(new WsProvider(wsUrl)); }); - it('subscribes via subscribeNewHead', (done): void => { + it('subscribes via subscribeNewHeads', (done): void => { let count = 0; rpc.chain - .subscribeNewHead() + .subscribeNewHeads() .subscribe((header: Header): void => { expect(header).toBeInstanceOf(ClassOf('Header')); diff --git a/packages/rpc-core/README.md b/packages/rpc-core/README.md index 69f1adfa28..1510cd4230 100644 --- a/packages/rpc-core/README.md +++ b/packages/rpc-core/README.md @@ -60,7 +60,7 @@ Retrieving best header via subscription - ```js api.chain rpc - .subscribeNewHead() + .subscribeNewHeads() .subscribe( (header) => { console.log(`best #${header.blockNumber}`); diff --git a/packages/rpc-core/src/cached.spec.ts b/packages/rpc-core/src/cached.spec.ts index f2634bdf3b..1df92d0e66 100644 --- a/packages/rpc-core/src/cached.spec.ts +++ b/packages/rpc-core/src/cached.spec.ts @@ -24,8 +24,8 @@ describe('Cached Observables', (): void => { }); it('creates a single observable for subscriptions (multiple calls, no arguments)', (): void => { - const observable1 = rpc.chain.subscribeNewHead(); - const observable2 = rpc.chain.subscribeNewHead(); + const observable1 = rpc.chain.subscribeNewHeads(); + const observable2 = rpc.chain.subscribeNewHeads(); expect(observable2).toBe(observable1); }); @@ -45,8 +45,8 @@ describe('Cached Observables', (): void => { }); it('clears cache if there are no more subscribers', (): void => { - const observable1 = rpc.chain.subscribeNewHead(); - const observable2 = rpc.chain.subscribeNewHead(); + const observable1 = rpc.chain.subscribeNewHeads(); + const observable2 = rpc.chain.subscribeNewHeads(); expect(observable1).toBe(observable2); @@ -57,14 +57,14 @@ describe('Cached Observables', (): void => { sub2.unsubscribe(); // No more subscribers, now create a new observable - const observable3 = rpc.chain.subscribeNewHead(); + const observable3 = rpc.chain.subscribeNewHeads(); expect(observable3).not.toBe(observable1); }); it('creates different observables for different methods but same arguments', (): void => { // @ts-ignore - const observable1 = rpc.chain.subscribeNewHead([123]); + const observable1 = rpc.chain.subscribeNewHeads([123]); const observable2 = rpc.state.subscribeStorage([123]); expect(observable2).not.toBe(observable1); diff --git a/packages/rpc-core/src/jsonrpc.types.ts b/packages/rpc-core/src/jsonrpc.types.ts index 012f8c5960..8f2c6f7ab5 100644 --- a/packages/rpc-core/src/jsonrpc.types.ts +++ b/packages/rpc-core/src/jsonrpc.types.ts @@ -11,11 +11,11 @@ import { Codec, IExtrinsic } from '@polkadot/types/types'; export interface RpcInterface { author: { insertKey(keyType: Text | string, suri: Text | string, maybePublic?: Bytes | Uint8Array | string): Observable; + pendingExtrinsics(): Observable>; removeExtrinsic(bytesOrHash: (ExtrinsicOrHash)[]): Observable>; rotateKeys(): Observable; - pendingExtrinsics(): Observable>; - submitExtrinsic(extrinsic: IExtrinsic): Observable; submitAndWatchExtrinsic(extrinsic: IExtrinsic): Observable; + submitExtrinsic(extrinsic: IExtrinsic): Observable; }; chain: { getBlock(hash?: Hash | Uint8Array | string): Observable; @@ -24,8 +24,8 @@ export interface RpcInterface { getHeader(hash?: Hash | Uint8Array | string): Observable
; getRuntimeVersion(hash?: Hash | Uint8Array | string): Observable; subscribeFinalizedHeads(): Observable
; + subscribeNewHeads(): Observable
; subscribeRuntimeVersion(): Observable; - subscribeNewHead(): Observable
; }; state: { call(method: Text | string, data: Bytes | Uint8Array | string, block?: Hash | Uint8Array | string): Observable; diff --git a/packages/rpc-core/src/replay.spec.ts b/packages/rpc-core/src/replay.spec.ts index 46f7bffce2..8084edff83 100644 --- a/packages/rpc-core/src/replay.spec.ts +++ b/packages/rpc-core/src/replay.spec.ts @@ -54,7 +54,7 @@ describe('replay', (): void => { it('unsubscribes as required', (done): void => { rpc.provider.unsubscribe = jest.fn(); - const subscription = rpc.chain.subscribeNewHead().subscribe((): void => { + const subscription = rpc.chain.subscribeNewHeads().subscribe((): void => { subscription.unsubscribe(); // There's a promise inside .unsubscribe(), wait a bit diff --git a/packages/rpc-provider/src/mock/index.ts b/packages/rpc-provider/src/mock/index.ts index 6385faf601..517be3457f 100644 --- a/packages/rpc-provider/src/mock/index.ts +++ b/packages/rpc-provider/src/mock/index.ts @@ -30,6 +30,7 @@ const SUBSCRIPTIONS: string[] = Array.prototype.concat.apply( .map(({ method, section }): string => `${section}_${method}` ) + .concat('chain_subscribeNewHead') ) ); diff --git a/packages/type-jsonrpc/src/chain.ts b/packages/type-jsonrpc/src/chain.ts index 9098619d15..19a796a479 100644 --- a/packages/type-jsonrpc/src/chain.ts +++ b/packages/type-jsonrpc/src/chain.ts @@ -47,9 +47,10 @@ const getRuntimeVersion: RpcMethodOpt = { type: 'RuntimeVersion' }; -const subscribeNewHead: RpcMethodOpt = { +const subscribeNewHeads: RpcMethodOpt = { description: 'Retrieves the best header via subscription', params: [], + // NOTE These still has the aliassed version, compatible with 1.x pubsub: [ 'newHead', 'subscribeNewHead', @@ -98,6 +99,6 @@ export default { getRuntimeVersion: createMethod(section, 'getRuntimeVersion', getRuntimeVersion), subscribeFinalizedHeads: createMethod(section, 'subscribeFinalizedHeads', subscribeFinalizedHeads), subscribeRuntimeVersion: createMethod(section, 'subscribeRuntimeVersion', subscribeRuntimeVersion), - subscribeNewHead: createMethod(section, 'subscribeNewHead', subscribeNewHead) + subscribeNewHeads: createMethod(section, 'subscribeNewHeads', subscribeNewHeads) } }; diff --git a/packages/types/src/scripts/interfacesTs.ts b/packages/types/src/scripts/interfacesTs.ts index 9223857067..dfb2ea5335 100644 --- a/packages/types/src/scripts/interfacesTs.ts +++ b/packages/types/src/scripts/interfacesTs.ts @@ -465,8 +465,10 @@ function generateRpcTypes (): void { const imports = createImports({ types: allImportedTypes }); - const body = Object.keys(interfaces).reduce((allSections, section): string[] => { - const allMethods = Object.values(interfaces[section].methods).map((method): string => { + const body = Object.keys(interfaces).sort().reduce((allSections, section): string[] => { + const allMethods = Object.keys(interfaces[section].methods).sort().map((key): string => { + const method = interfaces[section].methods[key]; + // FIXME These 2 are too hard to type, I give up if (method.method === 'getStorage') { setImports(imports, ['Codec']);