From 26ff33678e3d0e352d8833ccf0464b8f46eb54d8 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 11 Apr 2019 21:19:14 +0200 Subject: [PATCH] Store the genesisHash along with code & contracts (load check) (#982) * Store the genesisHash along with code & contracts (load check) * Cleanup hanging promises * contract:contract: -> contract:address: (storage) * Update store.ts --- packages/app-contracts/src/Code.tsx | 10 +++- packages/app-contracts/src/Instantiate.tsx | 10 +++- packages/app-contracts/src/index.tsx | 5 ++ packages/app-contracts/src/store.ts | 60 +++++++++++++++------- packages/app-contracts/src/types.ts | 19 ++++--- packages/ui-api/src/Api.tsx | 10 +++- packages/ui-api/src/index.ts | 3 +- 7 files changed, 84 insertions(+), 33 deletions(-) diff --git a/packages/app-contracts/src/Code.tsx b/packages/app-contracts/src/Code.tsx index be4e903072..94d73edfcc 100644 --- a/packages/app-contracts/src/Code.tsx +++ b/packages/app-contracts/src/Code.tsx @@ -225,7 +225,10 @@ class Deploy extends React.PureComponent { return; } - store.saveCode(new Hash(codeHash), { abi, name }); + store.saveCode(new Hash(codeHash), { abi, name }).catch((error) => { + console.error('Unable to save code', error); + }); + this.redirect(); } @@ -240,7 +243,10 @@ class Deploy extends React.PureComponent { return; } - store.saveCode(codeHash as Hash, { abi, name }); + store.saveCode(codeHash as Hash, { abi, name }).catch((error) => { + console.error('Unable to save code', error); + }); + this.redirect(); }); } diff --git a/packages/app-contracts/src/Instantiate.tsx b/packages/app-contracts/src/Instantiate.tsx index 102e31f512..cc40d1f7db 100644 --- a/packages/app-contracts/src/Instantiate.tsx +++ b/packages/app-contracts/src/Instantiate.tsx @@ -329,7 +329,10 @@ class Create extends React.PureComponent { return; } - store.saveContract(new AccountId(address), { abi, name }); + store.saveContract(new AccountId(address), { abi, name }).catch((error) => { + console.error('Unable to save contract', error); + }); + this.redirect(); } @@ -344,7 +347,10 @@ class Create extends React.PureComponent { return; } - store.saveContract(address as AccountId, { abi, name }); + store.saveContract(address as AccountId, { abi, name }).catch((error) => { + console.error('Unable to save contract', error); + }); + this.redirect(); }); } diff --git a/packages/app-contracts/src/index.tsx b/packages/app-contracts/src/index.tsx index 67df4a03fe..e99f4fc573 100644 --- a/packages/app-contracts/src/index.tsx +++ b/packages/app-contracts/src/index.tsx @@ -34,6 +34,11 @@ class App extends React.PureComponent { store.on('new-code', this.triggerUpdate); store.on('new-contract', this.triggerUpdate); + // since we have a dep on the async API, we load here + store.loadAll().catch(() => { + // noop, handled internally + }); + this.state = { tabs: [ { diff --git a/packages/app-contracts/src/store.ts b/packages/app-contracts/src/store.ts index 3028828bd1..c1ef472283 100644 --- a/packages/app-contracts/src/store.ts +++ b/packages/app-contracts/src/store.ts @@ -7,9 +7,11 @@ import { CodeJson, ContractJson } from './types'; import EventEmitter from 'eventemitter3'; import store from 'store'; import { AccountId, ContractAbi, Hash } from '@polkadot/types'; +import { api } from '@polkadot/ui-api'; -const KEY_CODE = 'contract:code:'; -const KEY_CONTRACT = 'contract:contract:'; +const PREFIX = 'contract:'; +const KEY_CODE = `${PREFIX}code:`; +const KEY_CONTRACT = `${PREFIX}addr:`; const codeRegex = new RegExp(`^${KEY_CODE}`, ''); const contractRegex = new RegExp(`^${KEY_CONTRACT}`, ''); @@ -21,18 +23,6 @@ class Store extends EventEmitter { private allCode: { [index: string]: CodeStored } = {}; private allContracts: { [index: string]: ContractStored } = {}; - constructor () { - super(); - - store.each((json: CodeJson | ContractJson, key: string) => { - if (codeRegex.test(key)) { - this.addCode(json as CodeJson); - } else if (contractRegex.test(key)) { - this.addContract(json as ContractJson); - } - }); - } - get hasCode (): boolean { return Object.keys(this.allCode).length !== 0; } @@ -57,22 +47,56 @@ class Store extends EventEmitter { return this.allContracts[address]; } - saveCode (codeHash: Hash, partial: Partial) { - const json = { ...partial, codeHash: codeHash.toHex() } as CodeJson; + async saveCode (codeHash: Hash, partial: Partial) { + await api.isReady; + + const json = { + ...partial, + codeHash: codeHash.toHex(), + genesisHash: api.genesisHash.toHex() + } as CodeJson; store.set(`${KEY_CODE}${json.codeHash}`, json); this.addCode(json); } - saveContract (address: AccountId, partial: Partial) { - const json = { ...partial, address: address.toString() } as ContractJson; + async saveContract (address: AccountId, partial: Partial) { + await api.isReady; + + const json = { + ...partial, + address: address.toString(), + genesisHash: api.genesisHash.toHex() + } as ContractJson; store.set(`${KEY_CONTRACT}${address}`, json); this.addContract(json); } + async loadAll () { + try { + await api.isReady; + + const genesisHash = api.genesisHash.toHex(); + + store.each((json: CodeJson | ContractJson, key: string) => { + if (json && json.genesisHash !== genesisHash) { + return; + } + + if (codeRegex.test(key)) { + this.addCode(json as CodeJson); + } else if (contractRegex.test(key)) { + this.addContract(json as ContractJson); + } + }); + } catch (error) { + console.error('Unable to load contracts', error); + } + } + private addCode (json: CodeJson) { try { this.allCode[json.codeHash] = { diff --git a/packages/app-contracts/src/types.ts b/packages/app-contracts/src/types.ts index ef011cf032..5a68d2110e 100644 --- a/packages/app-contracts/src/types.ts +++ b/packages/app-contracts/src/types.ts @@ -12,14 +12,17 @@ export type LocationProps = { export type ComponentProps = AppProps & LocationProps; -export type CodeJson = { - abi?: string | null, - codeHash: string, - name: string +type BaseInfo = { + name: string, + genesisHash: string }; -export type ContractJson = { - abi: string, - address: string, - name: string +export type CodeJson = BaseInfo & { + abi?: string | null, + codeHash: string +}; + +export type ContractJson = BaseInfo & { + abi: string, + address: string }; diff --git a/packages/ui-api/src/Api.tsx b/packages/ui-api/src/Api.tsx index 71db66c692..a2ebb925e8 100644 --- a/packages/ui-api/src/Api.tsx +++ b/packages/ui-api/src/Api.tsx @@ -18,6 +18,8 @@ import { formatBalance, isTestChain } from '@polkadot/util'; import ApiContext from './ApiContext'; +let api: ApiPromise; + type Props = { children: React.ReactNode, queueExtrinsic: QueueTx$ExtrinsicAdd, @@ -29,6 +31,8 @@ type State = ApiProps & { chain?: string }; +export { api }; + export default class ApiWrapper extends React.PureComponent { state: State = {} as State; @@ -40,7 +44,7 @@ export default class ApiWrapper extends React.PureComponent { const signer = new ApiSigner(queueExtrinsic, queueSetTxStatus); const setApi = (provider: ProviderInterface): void => { - const api = new ApiPromise({ provider, signer }); + api = new ApiPromise({ provider, signer }); this.setState({ api }, () => { this.subscribeEvents(); @@ -49,10 +53,12 @@ export default class ApiWrapper extends React.PureComponent { const setApiUrl = (url: string = defaults.WS_URL): void => setApi(new WsProvider(url)); + api = new ApiPromise({ provider, signer }); + this.state = { isApiConnected: false, isApiReady: false, - api: new ApiPromise({ provider, signer }), + api, setApiUrl } as State; } diff --git a/packages/ui-api/src/index.ts b/packages/ui-api/src/index.ts index 9437aea63f..e0cb450546 100644 --- a/packages/ui-api/src/index.ts +++ b/packages/ui-api/src/index.ts @@ -2,12 +2,13 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import Api from './Api'; +import Api, { api } from './Api'; import ApiContext from './ApiContext'; export * from './with'; export { + api, Api, ApiContext };