diff --git a/packages/app-staking/src/Query/Validator.tsx b/packages/app-staking/src/Query/Validator.tsx index 005a4b5b80..085e614a03 100644 --- a/packages/app-staking/src/Query/Validator.tsx +++ b/packages/app-staking/src/Query/Validator.tsx @@ -3,12 +3,13 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { I18nProps } from '@polkadot/react-components/types'; -import { BlockNumber, Exposure, Hash, SessionIndex } from '@polkadot/types/interfaces'; +import { BlockNumber, Exposure, SessionIndex } from '@polkadot/types/interfaces'; import BN from 'bn.js'; import React, { useContext, useEffect, useState } from 'react'; import { Chart, Columar, Column } from '@polkadot/react-components'; import { ApiContext, withCalls } from '@polkadot/react-api'; +import { getHistoric } from '@polkadot/react-api/util'; import { formatBalance, formatNumber } from '@polkadot/util'; import translate from '../translate'; @@ -47,42 +48,23 @@ function Validator ({ blockCounts, className, currentIndex, startNumber, t, vali const [stakeChart, setStateChart] = useState(); useEffect((): void => { - const numbers: BN[] = []; - const checkLength = (api.consts.babe - ? api.consts.babe.epochDuration as BlockNumber - : new BN(500)).muln(2).divn(3); - const divisor = new BN('1'.padEnd(formatBalance.getDefaults().decimals + 1, '0')); + api.isReady.then(async (): Promise => { + const divisor = new BN('1'.padEnd(formatBalance.getDefaults().decimals + 1, '0')); + const values = await getHistoric(api, 'staking.stakers', [validatorId], { + interval: (api.consts.babe?.epochDuration as BlockNumber || new BN(500)).muln(2).divn(3), + max: SESSIONS, + startNumber + }); - api.isReady.then((): void => { - let currentNumber: BN = startNumber; - - // here we end up with more-or-less 6.66 days - while (startNumber.gtn(0) && numbers.length < SESSIONS) { - numbers.unshift(currentNumber); - currentNumber = currentNumber.sub(checkLength); - } - - setStakeLabels(numbers.map((bn): string => formatNumber(bn))); - - Promise - .all(numbers.map((at): Promise => - api.rpc.chain.getBlockHash(at as any) - )) - .then((hashes): Promise => - Promise.all(hashes.map((hash): Promise => - api.query.staking.stakers.at(hash, validatorId) as Promise - )) - ) - .then((exposures): void => { - setStateChart([ - exposures.map(({ total }): BN => - total.unwrap().div(divisor)) - // exposures.map(({ own }): BN => - // own.unwrap().div(divisor)), - // exposures.map(({ others }): BN => - // others.reduce((total, { value }): BN => total.add(value.unwrap()), new BN(0)).div(divisor)) - ]); - }); + setStakeLabels(values.map(([bn]): string => formatNumber(bn))); + setStateChart([ + values.map(([,, { total }]): BN => + total.unwrap().div(divisor)) + // exposures.map(({ own }): BN => + // own.unwrap().div(divisor)), + // exposures.map(({ others }): BN => + // others.reduce((total, { value }): BN => total.add(value.unwrap()), new BN(0)).div(divisor)) + ]); }); }, []); diff --git a/packages/react-api/src/util/hashes.ts b/packages/react-api/src/util/hashes.ts new file mode 100644 index 0000000000..59889f9de9 --- /dev/null +++ b/packages/react-api/src/util/hashes.ts @@ -0,0 +1,33 @@ +// Copyright 2017-2019 @polkadot/react-api authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { Hash } from '@polkadot/types/interfaces'; + +import BN from 'bn.js'; +import ApiPromise from '@polkadot/api/promise'; +import { bnToBn } from '@polkadot/util'; + +export interface HashesOptions { + interval: BN | number; + max: number; + startNumber: BN; +} + +export default async function getHashes (api: ApiPromise, { interval, max, startNumber }: HashesOptions): Promise<[BN, Hash][]> { + const numbers: BN[] = []; + const _interval = bnToBn(interval); + let currentNumber: BN = startNumber; + + while (numbers.length < max && currentNumber.gtn(0)) { + numbers.unshift(currentNumber); + + currentNumber = currentNumber.sub(_interval); + } + + const hashes = await Promise.all( + numbers.map((at): Promise => api.rpc.chain.getBlockHash(at as any)) + ); + + return numbers.map((bn, index): [BN, Hash] => [bn, hashes[index]]); +} diff --git a/packages/react-api/src/util/historic.ts b/packages/react-api/src/util/historic.ts new file mode 100644 index 0000000000..8a5421c32f --- /dev/null +++ b/packages/react-api/src/util/historic.ts @@ -0,0 +1,25 @@ +// Copyright 2017-2019 @polkadot/react-api authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { Hash } from '@polkadot/types/interfaces'; +import { Codec } from '@polkadot/types/types'; + +import BN from 'bn.js'; +import ApiPromise from '@polkadot/api/promise'; + +import getHashes, { HashesOptions } from './hashes'; + +export default async function getHistory (api: ApiPromise, endpoint: string, params: any[], options: HashesOptions): Promise<[BN, Hash, T][]> { + const [mod, fn] = endpoint.split('.'); + const numbers = await getHashes(api, options); + const results = await Promise.all(numbers.map(([, hash]): Promise => + api.query[mod][fn].at(hash, ...params) as Promise + )); + + return results.map((value, index): [BN, Hash, T] => [ + numbers[index][0], + numbers[index][1], + value + ]); +} diff --git a/packages/react-api/src/util/index.ts b/packages/react-api/src/util/index.ts index 057ba6f7e8..21801a5e8f 100644 --- a/packages/react-api/src/util/index.ts +++ b/packages/react-api/src/util/index.ts @@ -2,11 +2,15 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +import getHashes from './hashes'; +import getHistoric from './historic'; import intervalObservable from './intervalObservable'; import isEqual from './isEqual'; import triggerChange from './triggerChange'; export { + getHashes, + getHistoric, intervalObservable, isEqual, triggerChange