From 3113386510f23eb890f532ac68b4338cf9161e17 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Wed, 11 Jul 2018 14:57:35 +0200 Subject: [PATCH] Allow state.setStorage to handle key def inputs (#113) --- packages/api/src/create/interface.ts | 12 ++++- .../api/src/create/methodSetStorage.spec.js | 39 +++++++++++++++ packages/api/src/create/methodSetStorage.ts | 49 +++++++++++++++++++ packages/api/src/create/types.d.ts | 10 ++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 packages/api/src/create/methodSetStorage.spec.js create mode 100644 packages/api/src/create/methodSetStorage.ts create mode 100644 packages/api/src/create/types.d.ts diff --git a/packages/api/src/create/interface.ts b/packages/api/src/create/interface.ts index b6d0e631fe..cb16bbc4b4 100644 --- a/packages/api/src/create/interface.ts +++ b/packages/api/src/create/interface.ts @@ -5,14 +5,24 @@ import { Interface$Sections } from '@polkadot/jsonrpc/types'; import { ProviderInterface } from '@polkadot/api-provider/types'; import { ApiInterface$Section } from '../types'; +import { MethodCreator } from './types'; import interfaces from '@polkadot/jsonrpc'; import assert from '@polkadot/util/assert'; import isUndefined from '@polkadot/util/is/undefined'; import methodSend from './methodSend'; +import methodSetStorage from './methodSetStorage'; import methodSubscribe from './methodSubscribe'; +type RpcOverrides = { + [index: string]: MethodCreator +}; + +const overrides: RpcOverrides = { + 'state_getStorage': methodSetStorage +}; + export default function createInterface (provider: ProviderInterface, section: Interface$Sections): ApiInterface$Section { const definition = interfaces[section]; @@ -29,7 +39,7 @@ export default function createInterface (provider: ProviderInterface, section: I exposed[name] = def.isSubscription ? methodSubscribe(provider, rpcName, name, def) - : methodSend(provider, rpcName, name, def); + : (overrides[rpcName] || methodSend)(provider, rpcName, name, def); return exposed; }, {} as ApiInterface$Section); diff --git a/packages/api/src/create/methodSetStorage.spec.js b/packages/api/src/create/methodSetStorage.spec.js new file mode 100644 index 0000000000..4f079f9baa --- /dev/null +++ b/packages/api/src/create/methodSetStorage.spec.js @@ -0,0 +1,39 @@ +// Copyright 2017-2018 @polkadot/api authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import storage from '@polkadot/storage'; + +import createApi from '../index'; + +describe('methodSetStorage', () => { + let api; + let provider; + + beforeEach(() => { + provider = { + send: jest.fn((method, params) => { + return Promise.resolve('0x0102'); + }) + }; + api = createApi(provider); + }); + + it('sends without encoding/decoding when encoded key is provided', () => { + return api.state.getStorage(new Uint8Array([1, 2, 3])).then((value) => { + expect(value).toEqual(new Uint8Array([1, 2])); + }); + }); + + it('encodes key (with params), decoding response', () => { + return api.state + .getStorage( + storage.staking.public.freeBalanceOf, + '5EhmTa7fL6SdjgKXo9g6hetR6nHnRAmrtisoGFWEESjzECtY' + ) + .then((value) => { + expect(provider.send).toHaveBeenCalledWith('state_getStorage', ['0x11cf1094db4db43356b7787c3e59c39f']); + expect(value.toNumber()).toEqual(513); + }); + }); +}); diff --git a/packages/api/src/create/methodSetStorage.ts b/packages/api/src/create/methodSetStorage.ts new file mode 100644 index 0000000000..a5deb2c3fe --- /dev/null +++ b/packages/api/src/create/methodSetStorage.ts @@ -0,0 +1,49 @@ +// Copyright 2017-2018 @polkadot/api authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { Interfaces } from '@polkadot/jsonrpc/types'; +import { SectionItem } from '@polkadot/params/types'; +import { Storages } from '@polkadot/storage/types'; +import { ProviderInterface } from '@polkadot/api-provider/types'; +import { ApiInterface$Section$Method } from '../types'; + +import decodeParams from '@polkadot/params/decode'; +import createStorageKey from '@polkadot/storage/key'; +import ExtError from '@polkadot/util/ext/error'; +import isUndefined from '@polkadot/util/is/undefined'; +import signature from '@polkadot/params/signature'; + +import methodSend from './methodSend'; + +type KeyValues = [SectionItem, any]; +export default function createMethodSetStorage (provider: ProviderInterface, rpcName: string, name: string, method: SectionItem): ApiInterface$Section$Method { + const send = methodSend(provider, rpcName, name, method); + const tryCatch = (fn: () => any): any => { + try { + return fn(); + } catch (error) { + throw new ExtError(`${signature(method)}:: ${error.message}`, (error as ExtError).code, undefined); + } + }; + + const call = async (...values: Array): Promise => { + if (isUndefined(values[0]) || isUndefined(values[0].params)) { + return send.apply(null, values); + } + + const [keyType, ...params] = values as KeyValues; + const key: Uint8Array = tryCatch(() => + createStorageKey(keyType).apply(null, params) + ); + + const result = await send(key); + + return tryCatch(() => + // FIXME We don't do any conversion checks for the type, currently not an issue, but _could_ turn out to be problematic (since this is storage, apply no transforms) + decodeParams(keyType.type, result, 'poc-1').value + ); + }; + + return call as ApiInterface$Section$Method; +} diff --git a/packages/api/src/create/types.d.ts b/packages/api/src/create/types.d.ts new file mode 100644 index 0000000000..c2f1b201f6 --- /dev/null +++ b/packages/api/src/create/types.d.ts @@ -0,0 +1,10 @@ +// Copyright 2017-2018 @polkadot/api authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +import { Interfaces } from '@polkadot/jsonrpc/types'; +import { SectionItem } from '@polkadot/params/types'; +import { ProviderInterface } from '@polkadot/api-provider/types'; +import { ApiInterface$Section$Method } from '../types'; + +export type MethodCreator = (provider: ProviderInterface, rpcName: string, name: string, method: SectionItem) => ApiInterface$Section$Method;