From 3a08d2d98a7761be5628695da898fdbf7a6e82db Mon Sep 17 00:00:00 2001 From: Jaco Date: Tue, 31 May 2022 08:43:02 +0200 Subject: [PATCH] Split apiSystem connection (#7662) * Split apiSystem connection * Test init * Remove unused * typo --- packages/react-api/src/Api.tsx | 27 +++- packages/react-api/src/types.ts | 1 + .../react-components/src/AccountIndex.tsx | 2 +- packages/react-components/src/AccountName.tsx | 2 +- .../react-hooks/src/useDeriveAccountFlags.ts | 2 +- .../react-hooks/src/useDeriveAccountInfo.ts | 2 +- packages/react-hooks/src/useSystemApi.ts | 17 ++- packages/test-support/src/pages/Page.tsx | 125 +++++++++--------- 8 files changed, 103 insertions(+), 75 deletions(-) diff --git a/packages/react-api/src/Api.tsx b/packages/react-api/src/Api.tsx index 8d7a4414f0..de90a31c2c 100644 --- a/packages/react-api/src/Api.tsx +++ b/packages/react-api/src/Api.tsx @@ -60,8 +60,9 @@ export const DEFAULT_AUX = ['Aux1', 'Aux2', 'Aux3', 'Aux4', 'Aux5', 'Aux6', 'Aux const DISALLOW_EXTENSIONS: string[] = []; let api: ApiPromise; +let apiSystem: ApiPromise; -export { api }; +export { api, apiSystem }; function isKeyringLoaded () { try { @@ -216,23 +217,35 @@ async function createApi (apiUrl: string, signer: ApiSigner, onError: (error: un const isLight = apiUrl.startsWith('light://'); try { - const provider = isLight - ? new ScProvider(getWellKnownChain(apiUrl.replace('light://substrate-connect/', ''))) - : new WsProvider(apiUrl); + const providers = [0, 1].map(() => + isLight + ? new ScProvider(getWellKnownChain(apiUrl.replace('light://substrate-connect/', ''))) + : new WsProvider(apiUrl) + ); api = new ApiPromise({ - provider, + provider: providers[0], registry, signer, types, typesBundle, typesChain }); + apiSystem = new ApiPromise({ provider: providers[1] }); // See https://github.com/polkadot-js/api/pull/4672#issuecomment-1078843960 if (isLight) { - await provider.connect(); + for (let i = 0; i < providers.length; i++) { + await providers[i].connect(); + } } + + // Debug - overall provider stats + // setInterval((): void => { + // for (let i = 0; i < providers.length; i++) { + // console.log(i, JSON.stringify(providers[i].stats)); + // } + // }, 5000); } catch (error) { onError(error); } @@ -256,7 +269,7 @@ function Api ({ apiUrl, children, isElectron, store }: Props): React.ReactElemen ); const apiRelay = useApiUrl(relayUrls); const value = useMemo( - () => objectSpread({}, state, { api, apiEndpoint, apiError, apiRelay, apiUrl, createLink: createLink(apiUrl, isElectron), extensions, isApiConnected, isApiInitialized, isElectron, isWaitingInjected: !extensions }), + () => objectSpread({}, state, { api, apiEndpoint, apiError, apiRelay, apiSystem, apiUrl, createLink: createLink(apiUrl, isElectron), extensions, isApiConnected, isApiInitialized, isElectron, isWaitingInjected: !extensions }), [apiError, extensions, isApiConnected, isApiInitialized, isElectron, state, apiEndpoint, apiRelay, apiUrl] ); diff --git a/packages/react-api/src/types.ts b/packages/react-api/src/types.ts index d755b6c54b..21c200d7cc 100644 --- a/packages/react-api/src/types.ts +++ b/packages/react-api/src/types.ts @@ -35,6 +35,7 @@ export interface ApiProps extends ApiState { apiEndpoint: LinkOption | null; apiError: string | null; apiRelay: ApiPromise | null; + apiSystem: ApiPromise; apiUrl?: string; createLink: (path: string, apiUrl?: string) => string; extensions?: InjectedExtension[]; diff --git a/packages/react-components/src/AccountIndex.tsx b/packages/react-components/src/AccountIndex.tsx index 62484a7839..9f2fa97986 100644 --- a/packages/react-components/src/AccountIndex.tsx +++ b/packages/react-components/src/AccountIndex.tsx @@ -32,7 +32,7 @@ function AccountIndex ({ children, className = '', defaultValue, label, value }: [info] ); - if (!api.query.indices) { + if (!api || !api.query.indices) { return null; } diff --git a/packages/react-components/src/AccountName.tsx b/packages/react-components/src/AccountName.tsx index eca4440398..87791b9625 100644 --- a/packages/react-components/src/AccountName.tsx +++ b/packages/react-components/src/AccountName.tsx @@ -185,7 +185,7 @@ function AccountName ({ children, className = '', defaultName, label, onClick, o parentCache.set(cacheAddr, identity.parent.toString()); } - if (isFunction(api.query.identity?.identityOf)) { + if (api && isFunction(api.query.identity?.identityOf)) { setName(() => identity?.display ? extractIdentity(cacheAddr, identity) diff --git a/packages/react-hooks/src/useDeriveAccountFlags.ts b/packages/react-hooks/src/useDeriveAccountFlags.ts index 5d82377d23..725ae53ed1 100644 --- a/packages/react-hooks/src/useDeriveAccountFlags.ts +++ b/packages/react-hooks/src/useDeriveAccountFlags.ts @@ -11,7 +11,7 @@ import { useSystemApi } from './useSystemApi'; function useDeriveAccountFlagsImpl (value?: AccountId | Address | Uint8Array | string | null): DeriveAccountFlags | undefined { const api = useSystemApi(); - return useCall(api.derive.accounts.flags, [value]); + return useCall(api && api.derive.accounts.flags, [value]); } export const useDeriveAccountFlags = createNamedHook('useDeriveAccountFlags', useDeriveAccountFlagsImpl); diff --git a/packages/react-hooks/src/useDeriveAccountInfo.ts b/packages/react-hooks/src/useDeriveAccountInfo.ts index cdc5e75c89..90711e6e7a 100644 --- a/packages/react-hooks/src/useDeriveAccountInfo.ts +++ b/packages/react-hooks/src/useDeriveAccountInfo.ts @@ -11,7 +11,7 @@ import { useSystemApi } from './useSystemApi'; function useDeriveAccountInfoImpl (value?: AccountId | AccountIndex | Address | Uint8Array | string | null): DeriveAccountInfo | undefined { const api = useSystemApi(); - return useCall(api.derive.accounts.info, [value]); + return useCall(api && api.derive.accounts.info, [value]); } export const useDeriveAccountInfo = createNamedHook('useDeriveAccountInfo', useDeriveAccountInfoImpl); diff --git a/packages/react-hooks/src/useSystemApi.ts b/packages/react-hooks/src/useSystemApi.ts index b9b22ac3a1..6de86a06c6 100644 --- a/packages/react-hooks/src/useSystemApi.ts +++ b/packages/react-hooks/src/useSystemApi.ts @@ -3,15 +3,24 @@ import type { ApiPromise } from '@polkadot/api'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { createNamedHook } from './createNamedHook'; import { useApi } from './useApi'; -function useSystemApiImpl (): ApiPromise { - const { api, apiRelay } = useApi(); +function useSystemApiImpl (): ApiPromise | undefined { + const { apiRelay, apiSystem } = useApi(); + const [apiDefault, setApiDefault] = useState(); - return useMemo(() => apiRelay || api, [apiRelay, api]); + // This system API does not use the global ready, so we + // explicitly wait for it here + useEffect((): void => { + apiSystem && apiSystem.isReady + .then(setApiDefault) + .catch(console.error); + }, [apiSystem]); + + return useMemo(() => apiRelay || apiDefault, [apiRelay, apiDefault]); } export const useSystemApi = createNamedHook('useSystemApi', useSystemApiImpl); diff --git a/packages/test-support/src/pages/Page.tsx b/packages/test-support/src/pages/Page.tsx index 36433fdb8a..bea1184f8d 100644 --- a/packages/test-support/src/pages/Page.tsx +++ b/packages/test-support/src/pages/Page.tsx @@ -120,70 +120,75 @@ export abstract class Page { }); const noop = () => Promise.resolve(() => { /**/ }); - const mockApi: ApiProps = { - api: { - consts: { - babe: { - expectedBlockTime: new BN(1) - }, - democracy: { - enactmentPeriod: new BN(1) - }, - proxy: { - proxyDepositBase: new BN(1), - proxyDepositFactor: new BN(1) - } + const api = { + consts: { + babe: { + expectedBlockTime: new BN(1) }, - createType: () => ({ - defKeys: [] - }), - derive: { - accounts: { - info: noop - }, - balances: { - all: noop - }, - chain: { - bestNumber: noop - }, - democracy: { - locks: noop - }, - staking: { - account: noop - } + democracy: { + enactmentPeriod: new BN(1) }, - genesisHash: new TypeRegistry().createType('Hash', POLKADOT_GENESIS), - query: { - democracy: { - votingOf: noop - }, - identity: { - identityOf: noop - } - }, - registry: { - chainDecimals: [12], - chainTokens: ['Unit'], - lookup: { - names: [] - } - }, - tx: { - council: {}, - democracy: { - delegate: noop - }, - multisig: { - approveAsMulti: Object.assign(noop, { meta: { args: [] } }) - }, - proxy: { - removeProxies: noop - }, - utility: noop + proxy: { + proxyDepositBase: new BN(1), + proxyDepositFactor: new BN(1) } }, + createType: () => ({ + defKeys: [] + }), + derive: { + accounts: { + info: noop + }, + balances: { + all: noop + }, + chain: { + bestNumber: noop + }, + democracy: { + locks: noop + }, + staking: { + account: noop + } + }, + genesisHash: new TypeRegistry().createType('Hash', POLKADOT_GENESIS), + query: { + democracy: { + votingOf: noop + }, + identity: { + identityOf: noop + } + }, + registry: { + chainDecimals: [12], + chainTokens: ['Unit'], + lookup: { + names: [] + } + }, + tx: { + council: {}, + democracy: { + delegate: noop + }, + multisig: { + approveAsMulti: Object.assign(noop, { meta: { args: [] } }) + }, + proxy: { + removeProxies: noop + }, + utility: noop + } + }; + const mockApi: ApiProps = { + api, + apiSystem: { + ...api, + isReady: Promise.resolve(api) + }, systemName: 'substrate' } as unknown as ApiProps;