Track Finalised events on api-rx (as per promise) (#500)

* Track Finalised events on api-rx (as per promise)

* Align naming of tracking helper

* Remove wtf

* Warn on extrinsic not found

* Fix unused imports
This commit is contained in:
Jaco Greeff
2018-12-21 11:12:41 +01:00
committed by GitHub
parent addba69054
commit 82cbd9727d
5 changed files with 84 additions and 25 deletions
@@ -4,9 +4,12 @@
import { KeyringPair } from '@polkadot/keyring/types';
import { AnyNumber, AnyU8a } from '@polkadot/types/types';
import { ApiPromiseInterface, SubmittableSendResult } from './types';
import { SubmittableSendResult } from '../types';
import { ApiPromiseInterface } from './types';
import { EventRecord, Extrinsic, ExtrinsicStatus, Hash, Method, SignedBlock, u32 } from '@polkadot/types/index';
import { EventRecord, Extrinsic, ExtrinsicStatus, Hash, Method, SignedBlock } from '@polkadot/types/index';
import filterEvents from '../util/filterEvents';
export default class SubmittableExtrinsic extends Extrinsic {
private _api: ApiPromiseInterface;
@@ -17,24 +20,17 @@ export default class SubmittableExtrinsic extends Extrinsic {
this._api = api;
}
private checkStatus (statusCb: (result: SubmittableSendResult) => any): (status: ExtrinsicStatus) => Promise<void> {
// FIXME split into graph derivation once available
private trackStatus (statusCb: (result: SubmittableSendResult) => any): (status: ExtrinsicStatus) => Promise<void> {
return async (status: ExtrinsicStatus): Promise<void> => {
let events: Array<any> | undefined = undefined;
if (status.type === 'Finalised') {
const blockHash = status.value as Hash;
const { block: { extrinsics } }: SignedBlock = await this._api.rpc.chain.getBlock(blockHash);
const signedBlock: SignedBlock = await this._api.rpc.chain.getBlock(blockHash);
const allEvents: Array<EventRecord> = await this._api.query.system.events.at(blockHash) as any;
const index = extrinsics
.map((ext) => ext.hash.toHex())
.indexOf(this.hash.toHex());
if (index !== -1) {
events = allEvents.filter(({ phase }) =>
phase.type === 'ApplyExtrinsic' && (phase.value as u32).eqn(index)
);
}
events = filterEvents(this.hash, signedBlock, allEvents);
}
statusCb({
@@ -50,7 +46,7 @@ export default class SubmittableExtrinsic extends Extrinsic {
return this._api.rpc.author.submitExtrinsic(this);
}
return this._api.rpc.author.submitAndWatchExtrinsic(this, this.checkStatus(statusCb));
return this._api.rpc.author.submitAndWatchExtrinsic(this, this.trackStatus(statusCb));
}
sign (signerPair: KeyringPair, nonce: AnyNumber, blockHash?: AnyU8a): SubmittableExtrinsic {
+31 -10
View File
@@ -4,11 +4,14 @@
import { KeyringPair } from '@polkadot/keyring/types';
import { AnyNumber, AnyU8a } from '@polkadot/types/types';
import { ApiRxInterface, SubmittableSendResult } from './types';
import { SubmittableSendResult } from '../types';
import { ApiRxInterface } from './types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Extrinsic, ExtrinsicStatus, Method } from '@polkadot/types/index';
import { Observable, of, combineLatest } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Extrinsic, ExtrinsicStatus, Hash, Method } from '@polkadot/types/index';
import filterEvents from '../util/filterEvents';
export default class SubmittableExtrinsic extends Extrinsic {
private _api: ApiRxInterface;
@@ -19,15 +22,33 @@ export default class SubmittableExtrinsic extends Extrinsic {
this._api = api;
}
// FIXME split into graph derivation once available
private trackStatus = (status: ExtrinsicStatus): Observable<SubmittableSendResult> => {
if (status.type !== 'Finalised') {
return of({
status,
type: status.type
});
}
const blockHash = status.value as Hash;
return combineLatest(
this._api.rpc.chain.getBlock(blockHash),
this._api.query.system.events.at(blockHash)
).pipe(
map(([signedBlock, allEvents]) => ({
events: filterEvents(this.hash, signedBlock, allEvents as any),
status,
type: status.type
}))
);
}
send (): Observable<SubmittableSendResult> {
return this._api.rpc.author
.submitAndWatchExtrinsic(this)
.pipe(
map((status: ExtrinsicStatus) => ({
status,
type: status.type
}))
);
.pipe(switchMap(this.trackStatus));
}
sign (signerPair: KeyringPair, nonce: AnyNumber, blockHash?: AnyU8a): SubmittableExtrinsic {
+7 -1
View File
@@ -4,7 +4,7 @@
import { ProviderInterface } from '@polkadot/rpc-provider/types';
import { RpcRxInterface$Events } from '@polkadot/rpc-rx/types';
import { Hash, Metadata, RuntimeVersion } from '@polkadot/types/index';
import { EventRecord, ExtrinsicStatus, Hash, Metadata, RuntimeVersion } from '@polkadot/types/index';
import { Constructor } from '@polkadot/types/types';
export type ApiInterface$Events = RpcRxInterface$Events | 'ready';
@@ -33,3 +33,9 @@ export interface ApiOptions {
*/
types?: {[name: string]: Constructor};
}
export type SubmittableSendResult = {
events?: Array<EventRecord>,
status: ExtrinsicStatus,
type: string
};
+27
View File
@@ -0,0 +1,27 @@
// Copyright 2017-2018 @polkadot/api 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 { EventRecord, Hash, SignedBlock, u32 } from '@polkadot/types/index';
import l from './logging';
export default function filterEvents (extHash: Hash, { block: { extrinsics, header } }: SignedBlock, allEvents: Array<EventRecord>): Array<EventRecord> | undefined {
// extrinsics to hashes
const myHash = extHash.toHex();
const allHashes = extrinsics.map((ext) => ext.hash.toHex());
// find the index of our extrinsic in the block
const index = allHashes.indexOf(myHash);
// if we do get the block after Finalised, it _should_ be there
if (index === -1) {
l.warn(`block ${header.hash}: Unable to find extrinsic ${myHash} inside ${allHashes}`);
return;
}
return allEvents.filter(({ phase }) =>
// only ApplyExtrinsic has the extrinsic index
phase.type === 'ApplyExtrinsic' && (phase.value as u32).eqn(index)
);
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright 2017-2018 @polkadot/api 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 { logger } from '@polkadot/util';
const l = logger('api/util');
export default l;