From c4b278d9c40c20d79c6cd307d4fbe3caa7a6b132 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 30 Oct 2020 15:27:14 +0100 Subject: [PATCH 01/12] Cater for new/old contracts_call results --- packages/types/src/augment/registry.ts | 23 ++++++-- .../src/interfaces/contracts/definitions.ts | 34 ++++++++++-- .../types/src/interfaces/contracts/types.ts | 54 ++++++++++++++++--- 3 files changed, 96 insertions(+), 15 deletions(-) diff --git a/packages/types/src/augment/registry.ts b/packages/types/src/augment/registry.ts index 4b32c10c245b..16f2f0137630 100644 --- a/packages/types/src/augment/registry.ts +++ b/packages/types/src/augment/registry.ts @@ -14,7 +14,7 @@ import { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate'; import { EthereumAddress, StatementKind } from '@polkadot/types/interfaces/claims'; import { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective'; import { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus'; -import { AliveContractInfo, CodeHash, ContractCallRequest, ContractExecResult, ContractExecResultSuccess, ContractExecResultSuccessTo255, ContractExecResultTo255, ContractInfo, ContractStorageKey, Gas, HostFnWeights, InstructionWeights, PrefabWasmModule, PrefabWasmModuleReserved, Schedule, ScheduleTo212, ScheduleTo258, SeedOf, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts'; +import { AliveContractInfo, CodeHash, ContractCallRequest, ContractExecResult, ContractExecResultErr, ContractExecResultErrModule, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractInfo, ContractStorageKey, Gas, HostFnWeights, InstructionWeights, PrefabWasmModule, PrefabWasmModuleReserved, Schedule, ScheduleTo212, ScheduleTo258, SeedOf, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts'; import { ContractConstructorSpec, ContractContractSpec, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEventParamSpec, ContractEventSpec, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpec, ContractMessageSpec, ContractProject, ContractProjectContract, ContractProjectSource, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi'; import { AccountVote, AccountVoteSplit, AccountVoteStandard, Conviction, Delegations, PreimageStatus, PreimageStatusAvailable, PriorLock, PropIndex, Proposal, ProxyState, ReferendumIndex, ReferendumInfo, ReferendumInfoFinished, ReferendumInfoTo239, ReferendumStatus, Tally, Voting, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces/democracy'; import { ApprovalFlag, DefunctVoter, Renouncing, SetIndex, Vote, VoteIndex, VoteThreshold, VoterInfo } from '@polkadot/types/interfaces/elections'; @@ -487,9 +487,24 @@ declare module '@polkadot/types/types/registry' { ContractExecResultTo255: ContractExecResultTo255; 'Option': Option; 'Vec': Vec; - ContractExecResultSuccess: ContractExecResultSuccess; - 'Option': Option; - 'Vec': Vec; + ContractExecResultSuccessTo260: ContractExecResultSuccessTo260; + 'Option': Option; + 'Vec': Vec; + ContractExecResultTo260: ContractExecResultTo260; + 'Option': Option; + 'Vec': Vec; + ContractExecResultErrModule: ContractExecResultErrModule; + 'Option': Option; + 'Vec': Vec; + ContractExecResultErr: ContractExecResultErr; + 'Option': Option; + 'Vec': Vec; + ContractExecResultOk: ContractExecResultOk; + 'Option': Option; + 'Vec': Vec; + ContractExecResultResult: ContractExecResultResult; + 'Option': Option; + 'Vec': Vec; ContractExecResult: ContractExecResult; 'Option': Option; 'Vec': Vec; diff --git a/packages/types/src/interfaces/contracts/definitions.ts b/packages/types/src/interfaces/contracts/definitions.ts index 8bb4b84656fc..36d54c248f60 100644 --- a/packages/types/src/interfaces/contracts/definitions.ts +++ b/packages/types/src/interfaces/contracts/definitions.ts @@ -90,17 +90,45 @@ export default { Error: 'Null' } }, - ContractExecResultSuccess: { + ContractExecResultSuccessTo260: { flags: 'u32', data: 'Bytes', gasConsumed: 'u64' }, - ContractExecResult: { + ContractExecResultTo260: { _enum: { - Success: 'ContractExecResultSuccess', + Success: 'ContractExecResultSuccessTo260', Error: 'Null' } }, + ContractExecResultErrModule: { + index: 'u8', + error: 'u8', + message: 'Option' + }, + ContractExecResultErr: { + _enum: { + Other: 'Text', + CannotLookup: 'Null', + BadOrigin: 'Null', + Module: 'ContractExecResultErrModule' + } + }, + ContractExecResultOk: { + flags: 'u32', + data: 'Bytes' + }, + ContractExecResultResult: { + _enum: { + Ok: 'ContractExecResultOk', + Err: 'ContractExecResultErr' + } + }, + ContractExecResult: { + gasConsumed: 'u64', + debugMessage: 'Text', + result: 'ContractExecResult' + }, ContractInfo: { _enum: { Alive: 'AliveContractInfo', diff --git a/packages/types/src/interfaces/contracts/types.ts b/packages/types/src/interfaces/contracts/types.ts index 2276003a7b6b..4d9a1a2cad27 100644 --- a/packages/types/src/interfaces/contracts/types.ts +++ b/packages/types/src/interfaces/contracts/types.ts @@ -2,7 +2,7 @@ /* eslint-disable */ import { Compact, Enum, Option, Raw, Struct, U8aFixed } from '@polkadot/types/codec'; -import { Bytes, Null, bool, u32, u64, u8 } from '@polkadot/types/primitive'; +import { Bytes, Null, Text, bool, u32, u64, u8 } from '@polkadot/types/primitive'; import { AccountId, Balance, BlockNumber, Hash, Weight } from '@polkadot/types/interfaces/runtime'; /** @name AliveContractInfo */ @@ -30,17 +30,41 @@ export interface ContractCallRequest extends Struct { } /** @name ContractExecResult */ -export interface ContractExecResult extends Enum { - readonly isSuccess: boolean; - readonly asSuccess: ContractExecResultSuccess; - readonly isError: boolean; +export interface ContractExecResult extends Struct { + readonly gasConsumed: u64; + readonly debugMessage: Text; + readonly result: ContractExecResult; +} + +/** @name ContractExecResultErr */ +export interface ContractExecResultErr extends Enum { + readonly isOther: boolean; + readonly asOther: Text; + readonly isCannotLookup: boolean; + readonly isBadOrigin: boolean; + readonly isModule: boolean; + readonly asModule: ContractExecResultErrModule; } -/** @name ContractExecResultSuccess */ -export interface ContractExecResultSuccess extends Struct { +/** @name ContractExecResultErrModule */ +export interface ContractExecResultErrModule extends Struct { + readonly index: u8; + readonly error: u8; + readonly message: Option; +} + +/** @name ContractExecResultOk */ +export interface ContractExecResultOk extends Struct { readonly flags: u32; readonly data: Bytes; - readonly gasConsumed: u64; +} + +/** @name ContractExecResultResult */ +export interface ContractExecResultResult extends Enum { + readonly isOk: boolean; + readonly asOk: ContractExecResultOk; + readonly isErr: boolean; + readonly asErr: ContractExecResultErr; } /** @name ContractExecResultSuccessTo255 */ @@ -49,6 +73,13 @@ export interface ContractExecResultSuccessTo255 extends Struct { readonly data: Raw; } +/** @name ContractExecResultSuccessTo260 */ +export interface ContractExecResultSuccessTo260 extends Struct { + readonly flags: u32; + readonly data: Bytes; + readonly gasConsumed: u64; +} + /** @name ContractExecResultTo255 */ export interface ContractExecResultTo255 extends Enum { readonly isSuccess: boolean; @@ -56,6 +87,13 @@ export interface ContractExecResultTo255 extends Enum { readonly isError: boolean; } +/** @name ContractExecResultTo260 */ +export interface ContractExecResultTo260 extends Enum { + readonly isSuccess: boolean; + readonly asSuccess: ContractExecResultSuccessTo260; + readonly isError: boolean; +} + /** @name ContractInfo */ export interface ContractInfo extends Enum { readonly isAlive: boolean; From 0f50ecd467b1c12f05ce32cb658b1fc54d430c34 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 30 Oct 2020 15:28:52 +0100 Subject: [PATCH 02/12] Update packages/types/src/interfaces/contracts/definitions.ts --- packages/types/src/interfaces/contracts/definitions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/src/interfaces/contracts/definitions.ts b/packages/types/src/interfaces/contracts/definitions.ts index 36d54c248f60..e48935ea93ff 100644 --- a/packages/types/src/interfaces/contracts/definitions.ts +++ b/packages/types/src/interfaces/contracts/definitions.ts @@ -127,7 +127,7 @@ export default { ContractExecResult: { gasConsumed: 'u64', debugMessage: 'Text', - result: 'ContractExecResult' + result: 'ContractExecResultResult' }, ContractInfo: { _enum: { From 6899b380585ffcb0f5d491a264ede441560f14b6 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 30 Oct 2020 15:42:56 +0100 Subject: [PATCH 03/12] Allow RPC layer to output JSON --- packages/rpc-core/src/index.ts | 29 ++++++++++--------- packages/rpc-core/src/types.ts | 1 + .../typegen/src/generate/interfaceRegistry.ts | 2 ++ packages/types/src/augment/registry.ts | 5 +++- .../types/src/interfaces/contracts/types.ts | 2 +- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/packages/rpc-core/src/index.ts b/packages/rpc-core/src/index.ts index aa7325cb0bb2..9f47b497e782 100644 --- a/packages/rpc-core/src/index.ts +++ b/packages/rpc-core/src/index.ts @@ -21,6 +21,8 @@ interface StorageChangeSetJSON { changes: [string, string | null][]; } +type OutputType = 'json' | 'raw' | 'scale'; + const l = logger('rpc-core'); const EMPTY_META = { @@ -211,10 +213,11 @@ export default class Rpc implements RpcInterface { }, {} as RpcInterface[Section]); } - private _createMethodWithRaw (creator: (isRaw: boolean) => (...values: any[]) => Observable): RpcInterfaceMethod { - const call = creator(false) as Partial; + private _createMethodWithRaw (creator: (outputAs: OutputType) => (...values: any[]) => Observable): RpcInterfaceMethod { + const call = creator('scale') as Partial; - call.raw = creator(true); + call.json = creator('json'); + call.raw = creator('raw'); return call as RpcInterfaceMethod; } @@ -226,7 +229,7 @@ export default class Rpc implements RpcInterface { let memoized: null | RpcInterfaceMethod & memoizee.Memoized = null; // execute the RPC call, doing a registry swap for historic as applicable - const callWithRegistry = async (isRaw: boolean, values: any[]): Promise => { + const callWithRegistry = async (outputAs: OutputType, values: any[]): Promise => { const hash = hashIndex === -1 ? undefined : values[hashIndex] as Uint8Array; @@ -236,16 +239,16 @@ export default class Rpc implements RpcInterface { const params = this._formatInputs(registry, def, values); const data = await this.provider.send(rpcName, params.map((param): AnyJson => param.toJSON())) as AnyJson; - return isRaw - ? registry.createType('Raw', data) - : this._formatOutput(registry, method, def, params, data); + return outputAs === 'scale' + ? this._formatOutput(registry, method, def, params, data) + : registry.createType(outputAs === 'raw' ? 'Raw' : 'Json', data); }; - const creator = (isRaw: boolean) => (...values: any[]): Observable => { + const creator = (outputAs: OutputType) => (...values: any[]): Observable => { const isDelayed = (hashIndex !== -1 && !!values[hashIndex]) || (cacheIndex !== -1 && !!values[cacheIndex]); return new Observable((observer: Observer): VoidCallback => { - callWithRegistry(isRaw, values) + callWithRegistry(outputAs, values) .then((value): void => { observer.next(value); observer.complete(); @@ -297,7 +300,7 @@ export default class Rpc implements RpcInterface { const subType = `${section}_${updateType}`; let memoized: null | RpcInterfaceMethod & memoizee.Memoized = null; - const creator = (isRaw: boolean) => (...values: unknown[]): Observable => { + const creator = (outputAs: OutputType) => (...values: unknown[]): Observable => { return new Observable((observer: Observer): VoidCallback => { // Have at least an empty promise, as used in the unsubscribe let subscriptionPromise: Promise = Promise.resolve(null); @@ -322,9 +325,9 @@ export default class Rpc implements RpcInterface { try { observer.next( - isRaw - ? registry.createType('Raw', result) - : this._formatOutput(registry, method, def, params, result) + outputAs === 'scale' + ? this._formatOutput(registry, method, def, params, result) + : registry.createType(outputAs === 'raw' ? 'Raw' : 'Json', result) ); } catch (error) { observer.error(error); diff --git a/packages/rpc-core/src/types.ts b/packages/rpc-core/src/types.ts index f4eced4ce879..34f554460826 100644 --- a/packages/rpc-core/src/types.ts +++ b/packages/rpc-core/src/types.ts @@ -7,5 +7,6 @@ export * from './types.jsonrpc'; export interface RpcInterfaceMethod { (...params: any[]): Observable; + json (...params: any[]): Observable; raw (...params: any[]): Observable; } diff --git a/packages/typegen/src/generate/interfaceRegistry.ts b/packages/typegen/src/generate/interfaceRegistry.ts index a2639af8af2c..b0ea83badb0f 100644 --- a/packages/typegen/src/generate/interfaceRegistry.ts +++ b/packages/typegen/src/generate/interfaceRegistry.ts @@ -3,6 +3,7 @@ import Handlebars from 'handlebars'; +import Json from '@polkadot/types/codec/Json'; import Raw from '@polkadot/types/codec/Raw'; import { TypeRegistry } from '@polkadot/types/create'; import * as defaultDefinitions from '@polkadot/types/interfaces/definitions'; @@ -13,6 +14,7 @@ import { ModuleTypes } from '../util/imports'; const primitiveClasses = { ...defaultPrimitives, + Json, Raw }; diff --git a/packages/types/src/augment/registry.ts b/packages/types/src/augment/registry.ts index 16f2f0137630..f32a0446ac69 100644 --- a/packages/types/src/augment/registry.ts +++ b/packages/types/src/augment/registry.ts @@ -1,7 +1,7 @@ // Auto-generated via `yarn polkadot-types-from-defs`, do not edit /* eslint-disable */ -import { Compact, Option, Raw, Vec } from '@polkadot/types/codec'; +import { Compact, Json, Option, Raw, Vec } from '@polkadot/types/codec'; import { BitVec, Bytes, Data, DoNotConstruct, Null, StorageKey, Text, Type, U256, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types/primitive'; import { BlockAttestations, IncludedBlocks, MoreAttestations } from '@polkadot/types/interfaces/attestations'; import { RawAuraPreDigest } from '@polkadot/types/interfaces/aura'; @@ -129,6 +129,9 @@ declare module '@polkadot/types/types/registry' { 'Compact': Compact; 'Option': Option; 'Vec': Vec; + Json: Json; + 'Option': Option; + 'Vec': Vec; Raw: Raw; 'Option': Option; 'Vec': Vec; diff --git a/packages/types/src/interfaces/contracts/types.ts b/packages/types/src/interfaces/contracts/types.ts index 4d9a1a2cad27..1fba8fe879e1 100644 --- a/packages/types/src/interfaces/contracts/types.ts +++ b/packages/types/src/interfaces/contracts/types.ts @@ -33,7 +33,7 @@ export interface ContractCallRequest extends Struct { export interface ContractExecResult extends Struct { readonly gasConsumed: u64; readonly debugMessage: Text; - readonly result: ContractExecResult; + readonly result: ContractExecResultResult; } /** @name ContractExecResultErr */ From 5ec62a15649266aecc66db8b0f1b29cc4dbe6c2f Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 30 Oct 2020 15:50:09 +0100 Subject: [PATCH 04/12] Typing for json outputs --- packages/api/src/base/Decorate.ts | 2 ++ packages/api/src/checkTypes.manual.ts | 3 ++- packages/api/src/types/rpc.ts | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/api/src/base/Decorate.ts b/packages/api/src/base/Decorate.ts index 138d40fd1c70..f2ebca90e636 100644 --- a/packages/api/src/base/Decorate.ts +++ b/packages/api/src/base/Decorate.ts @@ -274,6 +274,8 @@ export default abstract class Decorate extends Events if (this.hasSubscriptions || !(methodName.startsWith('subscribe') || methodName.startsWith('unsubscribe'))) { (section as Record)[methodName] = decorateMethod(method, { methodName }) as unknown; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + (section as Record)[methodName].json = decorateMethod(method.json, { methodName }) as unknown; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access (section as Record)[methodName].raw = decorateMethod(method.raw, { methodName }) as unknown; } diff --git a/packages/api/src/checkTypes.manual.ts b/packages/api/src/checkTypes.manual.ts index 26adbaae19e5..e3493010c51b 100644 --- a/packages/api/src/checkTypes.manual.ts +++ b/packages/api/src/checkTypes.manual.ts @@ -115,7 +115,8 @@ async function rpc (api: ApiPromise): Promise { console.log('current balance:', balance.toString()); }); - // using raw + // using json & raw + await api.rpc.chain.getBlock.json('0x123456'); await api.rpc.chain.getBlock.raw('0x123456'); // using raw subs diff --git a/packages/api/src/types/rpc.ts b/packages/api/src/types/rpc.ts index 1bca3f4bc12f..15cbc3c69b74 100644 --- a/packages/api/src/types/rpc.ts +++ b/packages/api/src/types/rpc.ts @@ -10,10 +10,13 @@ import { Observable } from 'rxjs'; import { ApiTypes, Push, PromiseResult, RxResult, UnsubscribePromise } from './base'; export interface RpcRxResult extends RxResult { + json (...args: Parameters): Observable & Codec>; raw (...args: Parameters): Observable; } export interface RpcPromiseResult extends PromiseResult { + json (...args: Parameters): Promise & Codec>; + json (...args: Push, Callback & Codec>>): UnsubscribePromise; raw (...args: Parameters): Promise; raw (...args: Push, Callback>): UnsubscribePromise; } From 6b88c8455c9f1094b75811ac0ea12347cf313c10 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 30 Oct 2020 16:23:52 +0100 Subject: [PATCH 05/12] Convert results --- packages/api-contract/src/base/Contract.ts | 47 ++++++++++++++++++---- packages/api-contract/src/types.ts | 8 +++- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/packages/api-contract/src/base/Contract.ts b/packages/api-contract/src/base/Contract.ts index 746d2e06da62..e33e9492a932 100644 --- a/packages/api-contract/src/base/Contract.ts +++ b/packages/api-contract/src/base/Contract.ts @@ -4,7 +4,7 @@ import { ApiTypes, DecorateMethod } from '@polkadot/api/types'; import { SubmittableExtrinsic } from '@polkadot/api/submittable/types'; import { AccountId, ContractExecResult } from '@polkadot/types/interfaces'; -import { AnyJson, CodecArg } from '@polkadot/types/types'; +import { AnyJson, CodecArg, Registry } from '@polkadot/types/types'; import { AbiMessage, ContractCallOutcome } from '../types'; import { ContractRead, MapMessageExec, MapMessageRead } from './types'; @@ -19,6 +19,31 @@ import Base from './Base'; const ERROR_NO_CALL = 'Your node does not expose the contracts.call RPC. This is most probably due to a runtime configuration.'; +// map from a JSON result to current-style ContractExecResult +function mapResult (registry: Registry, result: Record): ContractExecResult { + if (!result.success && !result.error) { + return registry.createType('ContractExecResult', result); + } + + const from = registry.createType('ContractExecResultTo260', result); + + if (from.isSuccess) { + const s = from.asSuccess; + + return registry.createType('ContractExecResult', { + gasConsumed: s.gasConsumed, + ok: { + data: s.data, + flags: s.flags + } + }); + } + + // in the old format error has no additional information, + // map it as-is with an "unknown" error + return registry.createType('ContractExecResult', { err: { other: 'unknown' } }); +} + export default class Contract extends Base { public readonly address: AccountId; @@ -80,19 +105,25 @@ export default class Contract extends Base { return { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment send: this._decorateMethod((origin: string | AccountId | Uint8Array) => - this.api.rx.rpc.contracts.call({ + this.api.rx.rpc.contracts.call.json({ dest: this.address, gasLimit: this.#getGas(gasLimit), inputData: message.toU8a(params), origin, value }).pipe( - map((result: ContractExecResult): ContractCallOutcome => ({ - output: result.isSuccess && message.returnType - ? formatData(this.registry, result.asSuccess.data, message.returnType) - : null, - result - })) + map((json: Record): ContractCallOutcome => { + const { debugMessage, gasConsumed, result } = mapResult(this.registry, json); + + return { + debugMessage, + gasConsumed, + output: result.isOk && message.returnType + ? formatData(this.registry, result.asOk.data, message.returnType) + : null, + result + }; + }) ) ) }; diff --git a/packages/api-contract/src/types.ts b/packages/api-contract/src/types.ts index f5346a867356..b72f6ee82999 100644 --- a/packages/api-contract/src/types.ts +++ b/packages/api-contract/src/types.ts @@ -2,10 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import { ApiTypes } from '@polkadot/api/types'; -import { ContractExecResult, ContractSelector } from '@polkadot/types/interfaces'; +import { ContractExecResultResult, ContractSelector } from '@polkadot/types/interfaces'; import { Codec, CodecArg, TypeDef } from '@polkadot/types/types'; import ApiBase from '@polkadot/api/base'; +import { Text, u64 } from '@polkadot/types'; + import Abi from './Abi'; export interface ContractBase { @@ -51,8 +53,10 @@ export interface InterfaceContractCalls { } export interface ContractCallOutcome { + debugMessage: Text; + gasConsumed: u64; output: Codec | null; - result: ContractExecResult; + result: ContractExecResultResult; } export interface DecodedEvent { From aed7b4261ffa189dd4d47923b7c23ac328eea0af Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 31 Oct 2020 08:53:33 +0100 Subject: [PATCH 06/12] RPC compat mapping --- packages/api-contract/src/base/Contract.ts | 41 +++++++++++-------- packages/api-contract/src/types.ts | 4 +- packages/types/src/augment/registry.ts | 5 ++- .../src/interfaces/contracts/definitions.ts | 6 +++ .../types/src/interfaces/contracts/types.ts | 8 ++++ 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/packages/api-contract/src/base/Contract.ts b/packages/api-contract/src/base/Contract.ts index e33e9492a932..8160602ed843 100644 --- a/packages/api-contract/src/base/Contract.ts +++ b/packages/api-contract/src/base/Contract.ts @@ -20,12 +20,12 @@ import Base from './Base'; const ERROR_NO_CALL = 'Your node does not expose the contracts.call RPC. This is most probably due to a runtime configuration.'; // map from a JSON result to current-style ContractExecResult -function mapResult (registry: Registry, result: Record): ContractExecResult { - if (!result.success && !result.error) { - return registry.createType('ContractExecResult', result); +function mapResultExec (registry: Registry, json: Record): ContractExecResult { + if (!json.success && !json.error) { + return registry.createType('ContractExecResult', json); } - const from = registry.createType('ContractExecResultTo260', result); + const from = registry.createType('ContractExecResultTo260', json); if (from.isSuccess) { const s = from.asSuccess; @@ -41,7 +41,23 @@ function mapResult (registry: Registry, result: Record): Contra // in the old format error has no additional information, // map it as-is with an "unknown" error - return registry.createType('ContractExecResult', { err: { other: 'unknown' } }); + return registry.createType('ContractExecResult', { err: { other: '' } }); +} + +function mapOutcome (registry: Registry, message: AbiMessage, json: Record): ContractCallOutcome { + const { debugMessage, gasConsumed, result: execResult } = mapResultExec(registry, json); + const result = execResult.isOk + ? registry.createType('ContractExecResultCompat', { success: execResult.asOk }) + : registry.createType('ContractExecResultCompat', { error: execResult.asErr }); + + return { + debugMessage, + gasConsumed, + output: result.isSuccess && message.returnType + ? formatData(registry, result.asSuccess.data, message.returnType) + : null, + result + }; } export default class Contract extends Base { @@ -112,18 +128,9 @@ export default class Contract extends Base { origin, value }).pipe( - map((json: Record): ContractCallOutcome => { - const { debugMessage, gasConsumed, result } = mapResult(this.registry, json); - - return { - debugMessage, - gasConsumed, - output: result.isOk && message.returnType - ? formatData(this.registry, result.asOk.data, message.returnType) - : null, - result - }; - }) + map((json: Record) => + mapOutcome(this.registry, message, json) + ) ) ) }; diff --git a/packages/api-contract/src/types.ts b/packages/api-contract/src/types.ts index b72f6ee82999..cae41beb6944 100644 --- a/packages/api-contract/src/types.ts +++ b/packages/api-contract/src/types.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { ApiTypes } from '@polkadot/api/types'; -import { ContractExecResultResult, ContractSelector } from '@polkadot/types/interfaces'; +import { ContractExecResultCompat, ContractSelector } from '@polkadot/types/interfaces'; import { Codec, CodecArg, TypeDef } from '@polkadot/types/types'; import ApiBase from '@polkadot/api/base'; @@ -56,7 +56,7 @@ export interface ContractCallOutcome { debugMessage: Text; gasConsumed: u64; output: Codec | null; - result: ContractExecResultResult; + result: ContractExecResultCompat; } export interface DecodedEvent { diff --git a/packages/types/src/augment/registry.ts b/packages/types/src/augment/registry.ts index f32a0446ac69..61fb58c9aeaa 100644 --- a/packages/types/src/augment/registry.ts +++ b/packages/types/src/augment/registry.ts @@ -14,7 +14,7 @@ import { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate'; import { EthereumAddress, StatementKind } from '@polkadot/types/interfaces/claims'; import { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective'; import { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus'; -import { AliveContractInfo, CodeHash, ContractCallRequest, ContractExecResult, ContractExecResultErr, ContractExecResultErrModule, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractInfo, ContractStorageKey, Gas, HostFnWeights, InstructionWeights, PrefabWasmModule, PrefabWasmModuleReserved, Schedule, ScheduleTo212, ScheduleTo258, SeedOf, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts'; +import { AliveContractInfo, CodeHash, ContractCallRequest, ContractExecResult, ContractExecResultCompat, ContractExecResultErr, ContractExecResultErrModule, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractInfo, ContractStorageKey, Gas, HostFnWeights, InstructionWeights, PrefabWasmModule, PrefabWasmModuleReserved, Schedule, ScheduleTo212, ScheduleTo258, SeedOf, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts'; import { ContractConstructorSpec, ContractContractSpec, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEventParamSpec, ContractEventSpec, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpec, ContractMessageSpec, ContractProject, ContractProjectContract, ContractProjectSource, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi'; import { AccountVote, AccountVoteSplit, AccountVoteStandard, Conviction, Delegations, PreimageStatus, PreimageStatusAvailable, PriorLock, PropIndex, Proposal, ProxyState, ReferendumIndex, ReferendumInfo, ReferendumInfoFinished, ReferendumInfoTo239, ReferendumStatus, Tally, Voting, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces/democracy'; import { ApprovalFlag, DefunctVoter, Renouncing, SetIndex, Vote, VoteIndex, VoteThreshold, VoterInfo } from '@polkadot/types/interfaces/elections'; @@ -505,6 +505,9 @@ declare module '@polkadot/types/types/registry' { ContractExecResultOk: ContractExecResultOk; 'Option': Option; 'Vec': Vec; + ContractExecResultCompat: ContractExecResultCompat; + 'Option': Option; + 'Vec': Vec; ContractExecResultResult: ContractExecResultResult; 'Option': Option; 'Vec': Vec; diff --git a/packages/types/src/interfaces/contracts/definitions.ts b/packages/types/src/interfaces/contracts/definitions.ts index e48935ea93ff..b9e4f8ae12d7 100644 --- a/packages/types/src/interfaces/contracts/definitions.ts +++ b/packages/types/src/interfaces/contracts/definitions.ts @@ -118,6 +118,12 @@ export default { flags: 'u32', data: 'Bytes' }, + ContractExecResultCompat: { + _enum: { + Success: 'ContractExecResultOk', + Error: 'ContractExecResultErr' + } + }, ContractExecResultResult: { _enum: { Ok: 'ContractExecResultOk', diff --git a/packages/types/src/interfaces/contracts/types.ts b/packages/types/src/interfaces/contracts/types.ts index 1fba8fe879e1..08df6d1ee376 100644 --- a/packages/types/src/interfaces/contracts/types.ts +++ b/packages/types/src/interfaces/contracts/types.ts @@ -36,6 +36,14 @@ export interface ContractExecResult extends Struct { readonly result: ContractExecResultResult; } +/** @name ContractExecResultCompat */ +export interface ContractExecResultCompat extends Enum { + readonly isSuccess: boolean; + readonly asSuccess: ContractExecResultOk; + readonly isError: boolean; + readonly asError: ContractExecResultErr; +} + /** @name ContractExecResultErr */ export interface ContractExecResultErr extends Enum { readonly isOther: boolean; From 0caf76264e498c80d85d31ac3baf75db6de199a7 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 31 Oct 2020 10:00:15 +0100 Subject: [PATCH 07/12] Ensure RPC .json is exposed --- packages/api-contract/src/base/Contract.ts | 37 ++++++++++++---------- packages/api/src/types/rpc.ts | 17 +++++----- packages/rpc-core/src/index.ts | 27 ++++++---------- 3 files changed, 38 insertions(+), 43 deletions(-) diff --git a/packages/api-contract/src/base/Contract.ts b/packages/api-contract/src/base/Contract.ts index 8160602ed843..f7652fbda143 100644 --- a/packages/api-contract/src/base/Contract.ts +++ b/packages/api-contract/src/base/Contract.ts @@ -11,7 +11,8 @@ import { ContractRead, MapMessageExec, MapMessageRead } from './types'; import BN from 'bn.js'; import { map } from 'rxjs/operators'; import ApiBase from '@polkadot/api/base'; -import { assert, bnToBn, isFunction, isUndefined, stringCamelCase } from '@polkadot/util'; +import { Json } from '@polkadot/types'; +import { assert, bnToBn, isFunction, isObject, isUndefined, stringCamelCase } from '@polkadot/util'; import Abi from '../Abi'; import { formatData } from '../util'; @@ -20,7 +21,9 @@ import Base from './Base'; const ERROR_NO_CALL = 'Your node does not expose the contracts.call RPC. This is most probably due to a runtime configuration.'; // map from a JSON result to current-style ContractExecResult -function mapResultExec (registry: Registry, json: Record): ContractExecResult { +function mapResultExec (registry: Registry, json: AnyJson): ContractExecResult { + assert(isObject(json) && !Array.isArray(json), 'Invalid JSON result retrieved'); + if (!json.success && !json.error) { return registry.createType('ContractExecResult', json); } @@ -32,31 +35,33 @@ function mapResultExec (registry: Registry, json: Record): Cont return registry.createType('ContractExecResult', { gasConsumed: s.gasConsumed, - ok: { - data: s.data, - flags: s.flags + result: { + ok: { + data: s.data, + flags: s.flags + } } }); } // in the old format error has no additional information, // map it as-is with an "unknown" error - return registry.createType('ContractExecResult', { err: { other: '' } }); + return registry.createType('ContractExecResult', { result: { err: { other: '' } } }); } -function mapOutcome (registry: Registry, message: AbiMessage, json: Record): ContractCallOutcome { - const { debugMessage, gasConsumed, result: execResult } = mapResultExec(registry, json); - const result = execResult.isOk - ? registry.createType('ContractExecResultCompat', { success: execResult.asOk }) - : registry.createType('ContractExecResultCompat', { error: execResult.asErr }); +function mapOutcome (registry: Registry, message: AbiMessage, json: Json): ContractCallOutcome { + const { debugMessage, gasConsumed, result: execResult } = mapResultExec(registry, json.toJSON()); return { debugMessage, gasConsumed, - output: result.isSuccess && message.returnType - ? formatData(registry, result.asSuccess.data, message.returnType) + output: execResult.isOk && message.returnType + ? formatData(registry, execResult.asOk.data, message.returnType) : null, - result + result: registry.createType('ContractExecResultCompat', execResult.isOk + ? { success: execResult.asOk } + : { error: execResult.asErr } + ) }; } @@ -128,9 +133,7 @@ export default class Contract extends Base { origin, value }).pipe( - map((json: Record) => - mapOutcome(this.registry, message, json) - ) + map((json) => mapOutcome(this.registry, message, json)) ) ) }; diff --git a/packages/api/src/types/rpc.ts b/packages/api/src/types/rpc.ts index 15cbc3c69b74..08044a56ff15 100644 --- a/packages/api/src/types/rpc.ts +++ b/packages/api/src/types/rpc.ts @@ -1,27 +1,26 @@ // Copyright 2017-2020 @polkadot/api authors & contributors // SPDX-License-Identifier: Apache-2.0 -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { AnyFunction, Callback, Codec } from '@polkadot/types/types'; +import { AnyFunction, Callback } from '@polkadot/types/types'; import { Observable } from 'rxjs'; +import { Json, Raw } from '@polkadot/types/codec'; // eslint-disable-next-line @typescript-eslint/no-unused-vars import { ApiTypes, Push, PromiseResult, RxResult, UnsubscribePromise } from './base'; export interface RpcRxResult extends RxResult { - json (...args: Parameters): Observable & Codec>; - raw (...args: Parameters): Observable; + json (...args: Parameters): Observable; + raw (...args: Parameters): Observable; } export interface RpcPromiseResult extends PromiseResult { - json (...args: Parameters): Promise & Codec>; - json (...args: Push, Callback & Codec>>): UnsubscribePromise; - raw (...args: Parameters): Promise; - raw (...args: Push, Callback>): UnsubscribePromise; + json (...args: Parameters): Promise; + json (...args: Push, Callback>): UnsubscribePromise; + raw (...args: Parameters): Promise; + raw (...args: Push, Callback>): UnsubscribePromise; } -// FIXME The day TS has higher-kinded types, we can remove this hardcoded stuff export type RpcMethodResult = ApiType extends 'rxjs' ? RpcRxResult : RpcPromiseResult; diff --git a/packages/rpc-core/src/index.ts b/packages/rpc-core/src/index.ts index 9f47b497e782..0a4f2f651ccf 100644 --- a/packages/rpc-core/src/index.ts +++ b/packages/rpc-core/src/index.ts @@ -213,13 +213,16 @@ export default class Rpc implements RpcInterface { }, {} as RpcInterface[Section]); } - private _createMethodWithRaw (creator: (outputAs: OutputType) => (...values: any[]) => Observable): RpcInterfaceMethod { - const call = creator('scale') as Partial; + private _memomize (creator: (outputAs: OutputType) => (...values: any[]) => Observable): RpcInterfaceMethod & memoizee.Memoized { + const memoized = memoizee(creator('scale') as RpcInterfaceMethod, { + length: false, + normalizer: normalizer(this.#instanceId) + }); - call.json = creator('json'); - call.raw = creator('raw'); + memoized.json = creator('json'); + memoized.raw = creator('raw'); - return call as RpcInterfaceMethod; + return memoized; } private _createMethodSend (section: string, method: string, def: DefinitionRpc): RpcInterfaceMethod { @@ -272,10 +275,7 @@ export default class Rpc implements RpcInterface { ); }; - memoized = memoizee(this._createMethodWithRaw(creator), { - length: false, - normalizer: normalizer(this.#instanceId) - }); + memoized = this._memomize(creator); return memoized; } @@ -356,14 +356,7 @@ export default class Rpc implements RpcInterface { }).pipe(drr()); }; - memoized = memoizee(this._createMethodWithRaw(creator), { - // Dynamic length for argument - length: false, - // Normalize args so that different args that should be cached - // together are cached together. - // E.g.: `query.my.method('abc') === query.my.method(createType('AccountId', 'abc'));` - normalizer: normalizer(this.#instanceId) - }); + memoized = this._memomize(creator); return memoized; } From d4ae15512ea7ec1c701adbff32203cb91ecbdb14 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 31 Oct 2020 10:04:42 +0100 Subject: [PATCH 08/12] Remove compat layer --- packages/api-contract/src/base/Contract.ts | 11 ++++------- packages/api-contract/src/types.ts | 4 ++-- packages/types/src/augment/registry.ts | 5 +---- .../types/src/interfaces/contracts/definitions.ts | 6 ------ packages/types/src/interfaces/contracts/types.ts | 8 -------- 5 files changed, 7 insertions(+), 27 deletions(-) diff --git a/packages/api-contract/src/base/Contract.ts b/packages/api-contract/src/base/Contract.ts index f7652fbda143..b048219a5e5d 100644 --- a/packages/api-contract/src/base/Contract.ts +++ b/packages/api-contract/src/base/Contract.ts @@ -50,18 +50,15 @@ function mapResultExec (registry: Registry, json: AnyJson): ContractExecResult { } function mapOutcome (registry: Registry, message: AbiMessage, json: Json): ContractCallOutcome { - const { debugMessage, gasConsumed, result: execResult } = mapResultExec(registry, json.toJSON()); + const { debugMessage, gasConsumed, result } = mapResultExec(registry, json.toJSON()); return { debugMessage, gasConsumed, - output: execResult.isOk && message.returnType - ? formatData(registry, execResult.asOk.data, message.returnType) + output: result.isOk && message.returnType + ? formatData(registry, result.asOk.data, message.returnType) : null, - result: registry.createType('ContractExecResultCompat', execResult.isOk - ? { success: execResult.asOk } - : { error: execResult.asErr } - ) + result }; } diff --git a/packages/api-contract/src/types.ts b/packages/api-contract/src/types.ts index cae41beb6944..b72f6ee82999 100644 --- a/packages/api-contract/src/types.ts +++ b/packages/api-contract/src/types.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { ApiTypes } from '@polkadot/api/types'; -import { ContractExecResultCompat, ContractSelector } from '@polkadot/types/interfaces'; +import { ContractExecResultResult, ContractSelector } from '@polkadot/types/interfaces'; import { Codec, CodecArg, TypeDef } from '@polkadot/types/types'; import ApiBase from '@polkadot/api/base'; @@ -56,7 +56,7 @@ export interface ContractCallOutcome { debugMessage: Text; gasConsumed: u64; output: Codec | null; - result: ContractExecResultCompat; + result: ContractExecResultResult; } export interface DecodedEvent { diff --git a/packages/types/src/augment/registry.ts b/packages/types/src/augment/registry.ts index 61fb58c9aeaa..f32a0446ac69 100644 --- a/packages/types/src/augment/registry.ts +++ b/packages/types/src/augment/registry.ts @@ -14,7 +14,7 @@ import { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate'; import { EthereumAddress, StatementKind } from '@polkadot/types/interfaces/claims'; import { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective'; import { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus'; -import { AliveContractInfo, CodeHash, ContractCallRequest, ContractExecResult, ContractExecResultCompat, ContractExecResultErr, ContractExecResultErrModule, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractInfo, ContractStorageKey, Gas, HostFnWeights, InstructionWeights, PrefabWasmModule, PrefabWasmModuleReserved, Schedule, ScheduleTo212, ScheduleTo258, SeedOf, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts'; +import { AliveContractInfo, CodeHash, ContractCallRequest, ContractExecResult, ContractExecResultErr, ContractExecResultErrModule, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractInfo, ContractStorageKey, Gas, HostFnWeights, InstructionWeights, PrefabWasmModule, PrefabWasmModuleReserved, Schedule, ScheduleTo212, ScheduleTo258, SeedOf, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts'; import { ContractConstructorSpec, ContractContractSpec, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEventParamSpec, ContractEventSpec, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpec, ContractMessageSpec, ContractProject, ContractProjectContract, ContractProjectSource, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi'; import { AccountVote, AccountVoteSplit, AccountVoteStandard, Conviction, Delegations, PreimageStatus, PreimageStatusAvailable, PriorLock, PropIndex, Proposal, ProxyState, ReferendumIndex, ReferendumInfo, ReferendumInfoFinished, ReferendumInfoTo239, ReferendumStatus, Tally, Voting, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces/democracy'; import { ApprovalFlag, DefunctVoter, Renouncing, SetIndex, Vote, VoteIndex, VoteThreshold, VoterInfo } from '@polkadot/types/interfaces/elections'; @@ -505,9 +505,6 @@ declare module '@polkadot/types/types/registry' { ContractExecResultOk: ContractExecResultOk; 'Option': Option; 'Vec': Vec; - ContractExecResultCompat: ContractExecResultCompat; - 'Option': Option; - 'Vec': Vec; ContractExecResultResult: ContractExecResultResult; 'Option': Option; 'Vec': Vec; diff --git a/packages/types/src/interfaces/contracts/definitions.ts b/packages/types/src/interfaces/contracts/definitions.ts index b9e4f8ae12d7..e48935ea93ff 100644 --- a/packages/types/src/interfaces/contracts/definitions.ts +++ b/packages/types/src/interfaces/contracts/definitions.ts @@ -118,12 +118,6 @@ export default { flags: 'u32', data: 'Bytes' }, - ContractExecResultCompat: { - _enum: { - Success: 'ContractExecResultOk', - Error: 'ContractExecResultErr' - } - }, ContractExecResultResult: { _enum: { Ok: 'ContractExecResultOk', diff --git a/packages/types/src/interfaces/contracts/types.ts b/packages/types/src/interfaces/contracts/types.ts index 08df6d1ee376..1fba8fe879e1 100644 --- a/packages/types/src/interfaces/contracts/types.ts +++ b/packages/types/src/interfaces/contracts/types.ts @@ -36,14 +36,6 @@ export interface ContractExecResult extends Struct { readonly result: ContractExecResultResult; } -/** @name ContractExecResultCompat */ -export interface ContractExecResultCompat extends Enum { - readonly isSuccess: boolean; - readonly asSuccess: ContractExecResultOk; - readonly isError: boolean; - readonly asError: ContractExecResultErr; -} - /** @name ContractExecResultErr */ export interface ContractExecResultErr extends Enum { readonly isOther: boolean; From 157b178a02771c337f5b0589ac41474ec8043586 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 31 Oct 2020 10:24:32 +0100 Subject: [PATCH 09/12] Old error detection --- packages/api-contract/src/base/Contract.ts | 33 +++++++++------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/packages/api-contract/src/base/Contract.ts b/packages/api-contract/src/base/Contract.ts index b048219a5e5d..899be02653a8 100644 --- a/packages/api-contract/src/base/Contract.ts +++ b/packages/api-contract/src/base/Contract.ts @@ -11,7 +11,6 @@ import { ContractRead, MapMessageExec, MapMessageRead } from './types'; import BN from 'bn.js'; import { map } from 'rxjs/operators'; import ApiBase from '@polkadot/api/base'; -import { Json } from '@polkadot/types'; import { assert, bnToBn, isFunction, isObject, isUndefined, stringCamelCase } from '@polkadot/util'; import Abi from '../Abi'; @@ -21,10 +20,10 @@ import Base from './Base'; const ERROR_NO_CALL = 'Your node does not expose the contracts.call RPC. This is most probably due to a runtime configuration.'; // map from a JSON result to current-style ContractExecResult -function mapResultExec (registry: Registry, json: AnyJson): ContractExecResult { +function mapExecResult (registry: Registry, json: AnyJson): ContractExecResult { assert(isObject(json) && !Array.isArray(json), 'Invalid JSON result retrieved'); - if (!json.success && !json.error) { + if (!Object.keys(json).some((key) => ['error', 'success'].includes(key))) { return registry.createType('ContractExecResult', json); } @@ -49,19 +48,6 @@ function mapResultExec (registry: Registry, json: AnyJson): ContractExecResult { return registry.createType('ContractExecResult', { result: { err: { other: '' } } }); } -function mapOutcome (registry: Registry, message: AbiMessage, json: Json): ContractCallOutcome { - const { debugMessage, gasConsumed, result } = mapResultExec(registry, json.toJSON()); - - return { - debugMessage, - gasConsumed, - output: result.isOk && message.returnType - ? formatData(registry, result.asOk.data, message.returnType) - : null, - result - }; -} - export default class Contract extends Base { public readonly address: AccountId; @@ -129,9 +115,18 @@ export default class Contract extends Base { inputData: message.toU8a(params), origin, value - }).pipe( - map((json) => mapOutcome(this.registry, message, json)) - ) + }).pipe(map((json): ContractCallOutcome => { + const { debugMessage, gasConsumed, result } = mapExecResult(this.registry, json.toJSON()); + + return { + debugMessage, + gasConsumed, + output: result.isOk && message.returnType + ? formatData(this.registry, result.asOk.data, message.returnType) + : null, + result + }; + })) ) }; } From d712a55bafbf13520f47597a7ed59d8d6089fc4b Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 31 Oct 2020 10:26:59 +0100 Subject: [PATCH 10/12] Map to unknown --- packages/api-contract/src/base/Contract.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api-contract/src/base/Contract.ts b/packages/api-contract/src/base/Contract.ts index 899be02653a8..5e07693dd316 100644 --- a/packages/api-contract/src/base/Contract.ts +++ b/packages/api-contract/src/base/Contract.ts @@ -45,7 +45,7 @@ function mapExecResult (registry: Registry, json: AnyJson): ContractExecResult { // in the old format error has no additional information, // map it as-is with an "unknown" error - return registry.createType('ContractExecResult', { result: { err: { other: '' } } }); + return registry.createType('ContractExecResult', { result: { err: { other: 'unknown' } } }); } export default class Contract extends Base { From 85eb42573320eb2a92abd3840b403612df429959 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 31 Oct 2020 10:45:31 +0100 Subject: [PATCH 11/12] Update packages/rpc-core/src/index.ts --- packages/rpc-core/src/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rpc-core/src/index.ts b/packages/rpc-core/src/index.ts index 0a4f2f651ccf..867902e36135 100644 --- a/packages/rpc-core/src/index.ts +++ b/packages/rpc-core/src/index.ts @@ -215,7 +215,11 @@ export default class Rpc implements RpcInterface { private _memomize (creator: (outputAs: OutputType) => (...values: any[]) => Observable): RpcInterfaceMethod & memoizee.Memoized { const memoized = memoizee(creator('scale') as RpcInterfaceMethod, { - length: false, + // Dynamic length for argument + length: false, + // Normalize args so that different args that should be cached + // together are cached together. + // E.g.: `query.my.method('abc') === query.my.method(createType('AccountId', 'abc'));` normalizer: normalizer(this.#instanceId) }); From 4fa8aa032101e747fd2379236fab5ae355146751 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 31 Oct 2020 10:50:27 +0100 Subject: [PATCH 12/12] linting --- packages/rpc-core/src/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rpc-core/src/index.ts b/packages/rpc-core/src/index.ts index 867902e36135..3524f5e484d2 100644 --- a/packages/rpc-core/src/index.ts +++ b/packages/rpc-core/src/index.ts @@ -215,10 +215,10 @@ export default class Rpc implements RpcInterface { private _memomize (creator: (outputAs: OutputType) => (...values: any[]) => Observable): RpcInterfaceMethod & memoizee.Memoized { const memoized = memoizee(creator('scale') as RpcInterfaceMethod, { - // Dynamic length for argument - length: false, - // Normalize args so that different args that should be cached - // together are cached together. + // Dynamic length for argument + length: false, + // Normalize args so that different args that should be cached + // together are cached together. // E.g.: `query.my.method('abc') === query.my.method(createType('AccountId', 'abc'));` normalizer: normalizer(this.#instanceId) });