Add dryRun capability on Submittable (#2793)

* Add dryRun capability on Submittable

* Ordering, add to interface

* Dry run with signing

* Revert paymentInfo changes
This commit is contained in:
Jaco Greeff
2020-10-27 15:19:00 +01:00
committed by GitHub
parent ca2909e4ba
commit cf1c2ea58a
2 changed files with 56 additions and 32 deletions
+40 -23
View File
@@ -3,10 +3,10 @@
/* eslint-disable no-dupe-class-members */
import { Address, Call, Extrinsic, ExtrinsicEra, ExtrinsicStatus, Hash, Header, Index, RuntimeDispatchInfo } from '@polkadot/types/interfaces';
import { Address, ApplyExtrinsicResult, Call, Extrinsic, ExtrinsicEra, ExtrinsicStatus, Hash, Header, Index, RuntimeDispatchInfo } from '@polkadot/types/interfaces';
import { Callback, Codec, Constructor, IKeyringPair, Registry, SignatureOptions, ISubmittableResult } from '@polkadot/types/types';
import { ApiInterfaceRx, ApiTypes, SignerResult } from '../types';
import { AddressOrPair, SignerOptions, SubmittableExtrinsic, SubmittablePaymentResult, SubmittableResultResult, SubmittableResultSubscription, SubmittableThis } from './types';
import { AddressOrPair, SignerOptions, SubmittableExtrinsic, SubmittableDryRunResult, SubmittablePaymentResult, SubmittableResultResult, SubmittableResultSubscription, SubmittableThis } from './types';
import { Observable, of } from 'rxjs';
import { first, map, mapTo, mergeMap, switchMap, tap } from 'rxjs/operators';
@@ -39,11 +39,22 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
this.#ignoreStatusCb = apiType === 'rxjs';
}
// adds a transform to the result, applied before result is returned
withResultTransform (transform: (input: ISubmittableResult) => ISubmittableResult): this {
this.#transformResult = transform;
// dry run an extrinsic
public dryRun (account: AddressOrPair, optionsOrHash?: Partial<SignerOptions> | Uint8Array | string): SubmittableDryRunResult<ApiType> {
if (isString(optionsOrHash) || isU8a(optionsOrHash)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return decorateMethod(
() => api.rpc.system.dryRun(this.toHex(), optionsOrHash)
);
}
return this;
// eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call
return decorateMethod(
(): Observable<ApplyExtrinsicResult> =>
this.#observeSign(account, optionsOrHash).pipe(
switchMap(() => api.rpc.system.dryRun(this.toHex()))
)
)();
}
// calculate the payment info for this transaction (if signed and submitted)
@@ -51,7 +62,7 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
if (isString(optionsOrHash) || isU8a(optionsOrHash)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return decorateMethod(
() => api.rpc.payment.queryInfo(this.toHex(), optionsOrHash)
(): Observable<RuntimeDispatchInfo> => api.rpc.payment.queryInfo(this.toHex(), optionsOrHash)
);
}
@@ -68,7 +79,6 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
const eraOptions = this.#makeEraOptions(allOptions, signingInfo);
const signOptions = this.#makeSignOptions(eraOptions, {});
// add a fake signature to the extrinsic
this.signFake(address, signOptions);
return api.rpc.payment.queryInfo(this.toHex());
@@ -77,6 +87,24 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
)();
}
// send with an immediate Hash result
public send (): SubmittableResultResult<ApiType>;
// send with a status callback
public send (statusCb: Callback<ISubmittableResult>): SubmittableResultSubscription<ApiType>;
// send implementation for both immediate Hash and statusCb variants
public send (statusCb?: Callback<ISubmittableResult>): SubmittableResultResult<ApiType> | SubmittableResultSubscription<ApiType> {
const isSubscription = api.hasSubscriptions && (this.#ignoreStatusCb || !!statusCb);
// eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call
return decorateMethod(
isSubscription
? this.#observeSubscribe
: this.#observeSend
)(statusCb);
}
/**
* @description Sign a transaction, returning the this to allow chaining, i.e. .sign(...).send(). When options, e.g. nonce/blockHash are not specified, it will be inferred. To retrieve eg. nonce use `signAsync` (the preferred interface, this is provided for backwards compatibility)
* @deprecated
@@ -125,22 +153,11 @@ export default function createClass <ApiType extends ApiTypes> ({ api, apiType,
)(statusCb);
}
// send with an immediate Hash result
public send (): SubmittableResultResult<ApiType>;
// adds a transform to the result, applied before result is returned
withResultTransform (transform: (input: ISubmittableResult) => ISubmittableResult): this {
this.#transformResult = transform;
// send with a status callback
public send (statusCb: Callback<ISubmittableResult>): SubmittableResultSubscription<ApiType>;
// send implementation for both immediate Hash and statusCb variants
public send (statusCb?: Callback<ISubmittableResult>): SubmittableResultResult<ApiType> | SubmittableResultSubscription<ApiType> {
const isSubscription = api.hasSubscriptions && (this.#ignoreStatusCb || !!statusCb);
// eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call
return decorateMethod(
isSubscription
? this.#observeSubscribe
: this.#observeSend
)(statusCb);
return this;
}
#makeEraOptions = (options: Partial<SignerOptions>, { header, mortalLength, nonce }: { header: Header | null; mortalLength: number; nonce: Index }): SignatureOptions => {
+16 -9
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2020 @polkadot/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { AccountId, Address, DispatchError, DispatchInfo, Extrinsic, ExtrinsicStatus, EventRecord, Hash, RuntimeDispatchInfo } from '@polkadot/types/interfaces';
import { AccountId, Address, ApplyExtrinsicResult, DispatchError, DispatchInfo, Extrinsic, ExtrinsicStatus, EventRecord, Hash, RuntimeDispatchInfo } from '@polkadot/types/interfaces';
import { AnyNumber, Callback, Codec, IExtrinsicEra, IKeyringPair, Signer, ISubmittableResult } from '@polkadot/types/types';
import { ApiTypes } from '../types';
@@ -14,6 +14,11 @@ export interface SubmittableResultValue {
status: ExtrinsicStatus;
}
export type SubmittableDryRunResult<ApiType extends ApiTypes> =
ApiType extends 'rxjs'
? Observable<ApplyExtrinsicResult>
: Promise<ApplyExtrinsicResult>;
export type SubmittablePaymentResult<ApiType extends ApiTypes> =
ApiType extends 'rxjs'
? Observable<RuntimeDispatchInfo>
@@ -45,24 +50,26 @@ export interface SignerOptions {
export type AddressOrPair = IKeyringPair | string | AccountId | Address;
export interface SubmittableExtrinsic<ApiType extends ApiTypes, R extends ISubmittableResult = ISubmittableResult> extends Extrinsic {
withResultTransform (transform: (input: ISubmittableResult) => ISubmittableResult): this;
dryRun (account: AddressOrPair, options?: Partial<SignerOptions>): SubmittableDryRunResult<ApiType>;
paymentInfo (account: AddressOrPair, options?: Partial<SignerOptions>): SubmittablePaymentResult<ApiType>;
send(): SubmittableResultResult<ApiType>;
send (): SubmittableResultResult<ApiType>;
send(statusCb: Callback<R>): SubmittableResultSubscription<ApiType, R>;
send (statusCb: Callback<R>): SubmittableResultSubscription<ApiType, R>;
/**
* @deprecated
*/
sign(account: IKeyringPair, _options?: Partial<SignerOptions>): this;
sign (account: IKeyringPair, _options?: Partial<SignerOptions>): this;
signAsync(account: AddressOrPair, _options?: Partial<SignerOptions>): SubmittableThis<ApiType, this>;
signAsync (account: AddressOrPair, _options?: Partial<SignerOptions>): SubmittableThis<ApiType, this>;
signAndSend(account: AddressOrPair, options?: Partial<SignerOptions>): SubmittableResultResult<ApiType, R>;
signAndSend (account: AddressOrPair, options?: Partial<SignerOptions>): SubmittableResultResult<ApiType, R>;
signAndSend(account: AddressOrPair, statusCb: Callback<R>): SubmittableResultSubscription<ApiType>;
signAndSend (account: AddressOrPair, statusCb: Callback<R>): SubmittableResultSubscription<ApiType>;
signAndSend(account: AddressOrPair, options: Partial<SignerOptions>, statusCb?: Callback<R>): SubmittableResultSubscription<ApiType, R>;
signAndSend (account: AddressOrPair, options: Partial<SignerOptions>, statusCb?: Callback<R>): SubmittableResultSubscription<ApiType, R>;
withResultTransform (transform: (input: ISubmittableResult) => ISubmittableResult): this;
}