From 2875fdf2cf90024631427afe5810a72cad7578a7 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Mon, 11 Nov 2019 14:25:07 +0100 Subject: [PATCH] Wrap all derives in memo (like rpc-core) (#1564) --- .../api-derive/src/accounts/idAndIndex.ts | 6 ++-- packages/api-derive/src/accounts/idToIndex.ts | 9 +++-- packages/api-derive/src/accounts/indexToId.ts | 9 +++-- packages/api-derive/src/accounts/indexes.ts | 19 +++++------ packages/api-derive/src/accounts/info.ts | 9 +++-- packages/api-derive/src/balances/all.ts | 9 +++-- packages/api-derive/src/balances/fees.ts | 9 +++-- .../api-derive/src/balances/votingBalances.ts | 23 ++++++------- .../balances/votingBalancesNominatorsFor.ts | 9 +++-- packages/api-derive/src/chain/bestNumber.ts | 9 +++-- .../src/chain/bestNumberFinalized.ts | 9 +++-- .../api-derive/src/chain/bestNumberLag.ts | 9 +++-- packages/api-derive/src/chain/getHeader.ts | 9 +++-- .../api-derive/src/chain/subscribeNewHeads.ts | 9 +++-- packages/api-derive/src/contracts/fees.ts | 12 +++---- .../src/democracy/referendumInfo.ts | 9 +++-- .../src/democracy/referendumInfos.ts | 9 +++-- .../src/democracy/referendumVotesFor.ts | 9 +++-- .../api-derive/src/democracy/referendums.ts | 9 +++-- packages/api-derive/src/democracy/votes.ts | 19 +++++------ .../api-derive/src/elections/approvalsOf.ts | 9 +++-- .../api-derive/src/elections/approvalsOfAt.ts | 9 +++-- packages/api-derive/src/elections/info.ts | 6 ++-- .../src/elections/voterPositions.ts | 9 +++-- packages/api-derive/src/elections/voters.ts | 9 +++-- .../src/imOnline/receivedHeartbeats.ts | 9 +++-- packages/api-derive/src/session/eraLength.ts | 9 +++-- .../api-derive/src/session/eraProgress.ts | 9 +++-- packages/api-derive/src/session/indexes.ts | 9 +++-- packages/api-derive/src/session/info.ts | 6 ++-- .../api-derive/src/session/sessionProgress.ts | 9 +++-- .../api-derive/src/staking/controllers.ts | 9 +++-- packages/api-derive/src/staking/info.ts | 12 +++---- packages/api-derive/src/staking/infoStash.ts | 9 +++-- packages/api-derive/src/staking/overview.ts | 9 +++-- .../api-derive/src/staking/recentlyOffline.ts | 9 +++-- packages/api-derive/src/staking/validators.ts | 9 +++-- packages/api-derive/src/util/drr.ts | 8 ----- packages/api-derive/src/util/index.ts | 1 - packages/api-derive/src/util/memo.ts | 33 +++++++++++++++---- 40 files changed, 190 insertions(+), 216 deletions(-) delete mode 100644 packages/api-derive/src/util/drr.ts diff --git a/packages/api-derive/src/accounts/idAndIndex.ts b/packages/api-derive/src/accounts/idAndIndex.ts index ac5d98f072..ba17931070 100644 --- a/packages/api-derive/src/accounts/idAndIndex.ts +++ b/packages/api-derive/src/accounts/idAndIndex.ts @@ -11,7 +11,7 @@ import { isU8a } from '@polkadot/util'; import { decodeAddress } from '@polkadot/util-crypto'; import { createType } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; export type AccountIdAndIndex = [AccountId?, AccountIndex?]; @@ -54,6 +54,6 @@ function retrieve (api: ApiInterfaceRx, address: Address | AccountId | AccountIn * ``` */ export function idAndIndex (api: ApiInterfaceRx): (address?: Address | AccountId | AccountIndex | string | null) => Observable { - return (address?: Address | AccountId | AccountIndex | string | null): Observable => - retrieve(api, address).pipe(drr()); + return memo((address?: Address | AccountId | AccountIndex | string | null): Observable => + retrieve(api, address)); } diff --git a/packages/api-derive/src/accounts/idToIndex.ts b/packages/api-derive/src/accounts/idToIndex.ts index f767e55476..1bced43e07 100644 --- a/packages/api-derive/src/accounts/idToIndex.ts +++ b/packages/api-derive/src/accounts/idToIndex.ts @@ -9,7 +9,7 @@ import { Observable } from 'rxjs'; import { map, startWith } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name idToIndex @@ -26,12 +26,11 @@ import { drr } from '../util'; * ``` */ export function idToIndex (api: ApiInterfaceRx): (accountId: AccountId | string) => Observable { - return (accountId: AccountId | string): Observable => + return memo((accountId: AccountId | string): Observable => api.derive.accounts.indexes().pipe( startWith({}), map((indexes: AccountIndexes): AccountIndex | undefined => (indexes || {})[accountId.toString()] - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/accounts/indexToId.ts b/packages/api-derive/src/accounts/indexToId.ts index d3d68c7cd5..b7107cab85 100644 --- a/packages/api-derive/src/accounts/indexToId.ts +++ b/packages/api-derive/src/accounts/indexToId.ts @@ -10,7 +10,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { ENUMSET_SIZE } from '@polkadot/types/primitive/Generic/AccountIndex'; import { createType, ClassOf, Vec } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name indexToId @@ -28,7 +28,7 @@ import { drr } from '../util'; export function indexToId (api: ApiInterfaceRx): (accountIndex: AccountIndex | string) => Observable { const querySection = api.query.indices || api.query.balances; - return (_accountIndex: AccountIndex | string): Observable => { + return memo((_accountIndex: AccountIndex | string): Observable => { const accountIndex = _accountIndex instanceof ClassOf('AccountIndex') ? _accountIndex : createType('AccountIndex', _accountIndex); @@ -37,8 +37,7 @@ export function indexToId (api: ApiInterfaceRx): (accountIndex: AccountIndex | s startWith([]), map((accounts): AccountId | undefined => (accounts || [])[accountIndex.mod(ENUMSET_SIZE).toNumber()] - ), - drr() + ) ); - }; + }); } diff --git a/packages/api-derive/src/accounts/indexes.ts b/packages/api-derive/src/accounts/indexes.ts index 197994edaa..850cf042c4 100644 --- a/packages/api-derive/src/accounts/indexes.ts +++ b/packages/api-derive/src/accounts/indexes.ts @@ -9,9 +9,9 @@ import { AccountIndexes } from '../types'; import { Observable } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; import { ENUMSET_SIZE } from '@polkadot/types/primitive/Generic/AccountIndex'; -import { createType } from '@polkadot/types'; +import { createType, Vec } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; const enumsetSize = ENUMSET_SIZE.toNumber(); @@ -31,17 +31,17 @@ const enumsetSize = ENUMSET_SIZE.toNumber(); * ``` */ export function indexes (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => api.query.indices.nextEnumSet().pipe( // use the nextEnumSet (which is a counter of the number of sets) to construct // a range of values to query [0, 1, 2, ...]. Retrieve the full enum set for the // specific index - each query can return up to ENUMSET_SIZE (64) records, each // containing an AccountId - switchMap((next: AccountIndex): Observable => - api.query.indices.enumSet.multi([...Array(next.toNumber() + 1).keys()]) as Observable + switchMap((next: AccountIndex): Observable[]> => + api.query.indices.enumSet.multi>([...Array(next.toNumber() + 1).keys()]) ), - map((all: (AccountId[] | undefined)[]): AccountIndexes => - (all || []).reduce((result: AccountIndexes, list, outerIndex): AccountIndexes => { + map((all: AccountId[][]): AccountIndexes => + all.reduce((result: AccountIndexes, list, outerIndex): AccountIndexes => { (list || []).forEach((accountId, innerIndex): void => { // re-create the index based on position 0 is [0][0] and likewise // 64 (0..63 in first) is [1][0] (the first index value in set 2) @@ -51,7 +51,6 @@ export function indexes (api: ApiInterfaceRx): () => Observable }); return result; - }, {})), - drr() - ); + }, {})) + )); } diff --git a/packages/api-derive/src/accounts/info.ts b/packages/api-derive/src/accounts/info.ts index 6e3776fc76..3e4b4226da 100644 --- a/packages/api-derive/src/accounts/info.ts +++ b/packages/api-derive/src/accounts/info.ts @@ -12,7 +12,7 @@ import { map, switchMap } from 'rxjs/operators'; import { Bytes, Option, u32 } from '@polkadot/types'; import { u8aToString } from '@polkadot/util'; -import { drr } from '../util'; +import { memo } from '../util'; function retrieveNick (api: ApiInterfaceRx, accountId?: AccountId): Observable { return (( @@ -33,7 +33,7 @@ function retrieveNick (api: ApiInterfaceRx, accountId?: AccountId): Observable Observable { - return (address?: AccountIndex | AccountId | Address | string | null): Observable => + return memo((address?: AccountIndex | AccountId | Address | string | null): Observable => api.derive.accounts.idAndIndex(address).pipe( switchMap(([accountId, accountIndex]): Observable<[DeriveAccountInfo, string?]> => combineLatest([ @@ -43,7 +43,6 @@ export function info (api: ApiInterfaceRx): (address?: AccountIndex | AccountId ), map(([{ accountId, accountIndex }, nickname]): DeriveAccountInfo => ({ accountId, accountIndex, nickname - })), - drr() - ); + })) + )); } diff --git a/packages/api-derive/src/balances/all.ts b/packages/api-derive/src/balances/all.ts index 939debb847..72530f6822 100644 --- a/packages/api-derive/src/balances/all.ts +++ b/packages/api-derive/src/balances/all.ts @@ -12,7 +12,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { Option, Vec, createType } from '@polkadot/types'; import { bnMax } from '@polkadot/util'; -import { drr } from '../util'; +import { memo } from '../util'; type ResultBalance = [Balance, Balance, BalanceLock[], Option]; type Result = [AccountId, BlockNumber, ResultBalance, Index]; @@ -76,7 +76,7 @@ function queryBalances (api: ApiInterfaceRx, accountId: AccountId): Observable Observable { - return (address: AccountIndex | AccountId | Address | string): Observable => + return memo((address: AccountIndex | AccountId | Address | string): Observable => api.derive.accounts.info(address).pipe( switchMap(({ accountId }): Observable => (accountId @@ -94,7 +94,6 @@ export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId | : of([createType('AccountId'), createType('BlockNumber'), [createType('Balance'), createType('Balance'), createType('Vec'), createType('Option', null)], createType('Index')]) ) ), - map(calcBalances), - drr() - ); + map(calcBalances) + )); } diff --git a/packages/api-derive/src/balances/fees.ts b/packages/api-derive/src/balances/fees.ts index 69300efa5e..e477622c32 100644 --- a/packages/api-derive/src/balances/fees.ts +++ b/packages/api-derive/src/balances/fees.ts @@ -9,7 +9,7 @@ import { DerivedFees } from '../types'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; -import { drr } from '../util'; +import { memo } from '../util'; type Result = [Balance, Balance, Balance, Balance, Balance]; @@ -56,7 +56,7 @@ export function fees (api: ApiInterfaceRx): () => Observable { ? queryV2 : queryV1; - return (): Observable => + return memo((): Observable => query(api).pipe( map(([creationFee, existentialDeposit, transferFee, transactionBaseFee, transactionByteFee]): DerivedFees => ({ creationFee, @@ -64,7 +64,6 @@ export function fees (api: ApiInterfaceRx): () => Observable { transactionBaseFee, transactionByteFee, transferFee - })), - drr() - ); + })) + )); } diff --git a/packages/api-derive/src/balances/votingBalances.ts b/packages/api-derive/src/balances/votingBalances.ts index a38600a849..8aed3a490e 100644 --- a/packages/api-derive/src/balances/votingBalances.ts +++ b/packages/api-derive/src/balances/votingBalances.ts @@ -3,23 +3,20 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { AccountId, AccountIndex, Address } from '@polkadot/types/interfaces'; +import { DerivedBalances } from '../types'; import { combineLatest, Observable, of } from 'rxjs'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { DerivedBalances } from '../types'; -import { drr } from '../util'; +import { memo } from '../util'; export function votingBalances (api: ApiInterfaceRx): (addresses?: (AccountId | AccountIndex | Address | string)[]) => Observable { - return (addresses?: (AccountId | AccountIndex | Address | string)[]): Observable => - ( - !addresses || !addresses.length - ? of([] as DerivedBalances[]) - : combineLatest( - addresses.map((accountId): Observable => - api.derive.balances.all(accountId)) - ) - ).pipe( - drr() - ); + return memo((addresses?: (AccountId | AccountIndex | Address | string)[]): Observable => + !addresses || !addresses.length + ? of([] as DerivedBalances[]) + : combineLatest( + addresses.map((accountId): Observable => + api.derive.balances.all(accountId)) + ) + ); } diff --git a/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts b/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts index bfe53015ec..8d96c691a2 100644 --- a/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts +++ b/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts @@ -10,10 +10,10 @@ import { switchMap } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { Vec } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; export function votingBalancesNominatorsFor (api: ApiInterfaceRx): (address: AccountId | AccountIndex | Address | string) => Observable { - return (address: AccountId | AccountIndex | Address | string): Observable => + return memo((address: AccountId | AccountIndex | Address | string): Observable => api.derive.accounts.info(address).pipe( switchMap(({ accountId }): Observable => accountId @@ -22,7 +22,6 @@ export function votingBalancesNominatorsFor (api: ApiInterfaceRx): (address: Acc ), switchMap((accounts): Observable => api.derive.balances.votingBalances(accounts) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/chain/bestNumber.ts b/packages/api-derive/src/chain/bestNumber.ts index 15facce531..474dba7a1f 100644 --- a/packages/api-derive/src/chain/bestNumber.ts +++ b/packages/api-derive/src/chain/bestNumber.ts @@ -8,7 +8,7 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name bestNumber @@ -23,9 +23,8 @@ import { drr } from '../util'; * ``` */ export function bestNumber (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => api.derive.chain.subscribeNewHeads().pipe( - map((header: Header): BlockNumber => header.number.unwrap()), - drr() - ); + map((header: Header): BlockNumber => header.number.unwrap()) + )); } diff --git a/packages/api-derive/src/chain/bestNumberFinalized.ts b/packages/api-derive/src/chain/bestNumberFinalized.ts index 6462c6ec6b..4afbd7cd61 100644 --- a/packages/api-derive/src/chain/bestNumberFinalized.ts +++ b/packages/api-derive/src/chain/bestNumberFinalized.ts @@ -8,7 +8,7 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name bestNumberFinalized @@ -24,9 +24,8 @@ import { drr } from '../util'; * ``` */ export function bestNumberFinalized (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => api.rpc.chain.subscribeFinalizedHeads().pipe( - map((header): BlockNumber => header.number.unwrap()), - drr() - ); + map((header): BlockNumber => header.number.unwrap()) + )); } diff --git a/packages/api-derive/src/chain/bestNumberLag.ts b/packages/api-derive/src/chain/bestNumberLag.ts index c9ad3af8a2..2f5e10827e 100644 --- a/packages/api-derive/src/chain/bestNumberLag.ts +++ b/packages/api-derive/src/chain/bestNumberLag.ts @@ -9,7 +9,7 @@ import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { createType } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name bestNumberLag @@ -25,14 +25,13 @@ import { drr } from '../util'; * ``` */ export function bestNumberLag (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => combineLatest([ api.derive.chain.bestNumber(), api.derive.chain.bestNumberFinalized() ]).pipe( map(([bestNumber, bestNumberFinalized]): BlockNumber => createType('BlockNumber', bestNumber.sub(bestNumberFinalized)) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/chain/getHeader.ts b/packages/api-derive/src/chain/getHeader.ts index 0bb2741759..af467e028c 100644 --- a/packages/api-derive/src/chain/getHeader.ts +++ b/packages/api-derive/src/chain/getHeader.ts @@ -11,7 +11,7 @@ import { catchError, map } from 'rxjs/operators'; import { Vec } from '@polkadot/types'; import { HeaderExtended } from '../type'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name bestNumberFinalized @@ -28,7 +28,7 @@ import { drr } from '../util'; * ``` */ export function getHeader (api: ApiInterfaceRx): (hash: Uint8Array | string) => Observable { - return (hash: Uint8Array | string): Observable => + return memo((hash: Uint8Array | string): Observable => combineLatest([ api.rpc.chain.getHeader(hash), api.query.session @@ -43,7 +43,6 @@ export function getHeader (api: ApiInterfaceRx): (hash: Uint8Array | string) => // we supplied an invalid hash. (Due to defaults, storeage will have an // empty value, so only the RPC is affected). So return undefined of() - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/chain/subscribeNewHeads.ts b/packages/api-derive/src/chain/subscribeNewHeads.ts index 950589a421..67b9bb8a7a 100644 --- a/packages/api-derive/src/chain/subscribeNewHeads.ts +++ b/packages/api-derive/src/chain/subscribeNewHeads.ts @@ -8,7 +8,7 @@ import { Observable, combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; import { HeaderExtended } from '../type'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name subscribeNewHeads @@ -24,14 +24,13 @@ import { drr } from '../util'; * ``` */ export function subscribeNewHeads (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => combineLatest([ api.rpc.chain.subscribeNewHeads(), api.derive.staking.validators() ]).pipe( map(([header, { validators }]): HeaderExtended => new HeaderExtended(header, validators) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/contracts/fees.ts b/packages/api-derive/src/contracts/fees.ts index 977d686f16..51257ec1e1 100644 --- a/packages/api-derive/src/contracts/fees.ts +++ b/packages/api-derive/src/contracts/fees.ts @@ -9,7 +9,7 @@ import BN from 'bn.js'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; -import { drr } from '../util'; +import { memo } from '../util'; type ResultV2 = [BN, BN, BN, BN, BN, BN, BN, BN, BN, BN]; @@ -51,8 +51,7 @@ function queryV1 (api: ApiInterfaceRx): Observable { parseResult([ callBaseFee, contractFee, createBaseFee, creationFee, ZERO, ZERO, ZERO, transactionBaseFee, transactionByteFee, transferFee ]) - ), - drr() + ) ); } @@ -104,7 +103,7 @@ function queryConstants (api: ApiInterfaceRx): Observable { * ``` */ export function fees (api: ApiInterfaceRx): () => Observable { - return (): Observable => { + return memo((): Observable => { if (api.query.contract && !api.query.contract.rentByteFee) { return queryV1(api); } @@ -119,8 +118,7 @@ export function fees (api: ApiInterfaceRx): () => Observable): Option { const info = optionInfo @@ -28,11 +28,10 @@ export function constructInfo (index: BN | number, optionInfo?: Option Observable> { - return (index: BN | number): Observable> => + return memo((index: BN | number): Observable> => api.query.democracy.referendumInfoOf>(index).pipe( map((optionInfo): Option => constructInfo(index, optionInfo) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/democracy/referendumInfos.ts b/packages/api-derive/src/democracy/referendumInfos.ts index 40c5b0e39a..080771e2b1 100644 --- a/packages/api-derive/src/democracy/referendumInfos.ts +++ b/packages/api-derive/src/democracy/referendumInfos.ts @@ -11,11 +11,11 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { Option, Vec } from '@polkadot/types'; import { ReferendumInfoExtended } from '../type'; -import { drr } from '../util'; +import { memo } from '../util'; import { constructInfo } from './referendumInfo'; export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) => Observable[]> { - return (ids: (BN | number)[] = []): Observable[]> => + return memo((ids: (BN | number)[] = []): Observable[]> => ( !ids || !ids.length ? of([] as Option[]) @@ -25,7 +25,6 @@ export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) = ids.map((id, index): Option => constructInfo(id, infos[index]) ) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/democracy/referendumVotesFor.ts b/packages/api-derive/src/democracy/referendumVotesFor.ts index 44f451800f..681ab8e580 100644 --- a/packages/api-derive/src/democracy/referendumVotesFor.ts +++ b/packages/api-derive/src/democracy/referendumVotesFor.ts @@ -11,10 +11,10 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { Vec, createType } from '@polkadot/types'; import { DerivedBalances, DerivedReferendumVote } from '../types'; -import { drr } from '../util'; +import { memo } from '../util'; export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | number) => Observable { - return (referendumId: BN | number): Observable => + return memo((referendumId: BN | number): Observable => api.query.democracy.votersFor>(referendumId).pipe( switchMap((votersFor): Observable<[Vec, Vote[], DerivedBalances[]]> => combineLatest([ @@ -29,7 +29,6 @@ export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | nu balance: balances[index].votingBalance || createType('Balance'), vote: votes[index] || createType('Vote') } as unknown as DerivedReferendumVote)) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/democracy/referendums.ts b/packages/api-derive/src/democracy/referendums.ts index 99355ca01a..9d2ee3953f 100644 --- a/packages/api-derive/src/democracy/referendums.ts +++ b/packages/api-derive/src/democracy/referendums.ts @@ -11,10 +11,10 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { Option } from '@polkadot/types'; import { ReferendumInfoExtended } from '../type'; -import { drr } from '../util'; +import { memo } from '../util'; export function referendums (api: ApiInterfaceRx): () => Observable[]> { - return (): Observable[]> => + return memo((): Observable[]> => api.queryMulti<[ReferendumIndex, ReferendumIndex]>([ api.query.democracy.nextTally, api.query.democracy.referendumCount @@ -27,7 +27,6 @@ export function referendums (api: ApiInterfaceRx): () => Observable Observable { - return (referendumId: BN, accountIds: AccountId[] = []): Observable => - ( - !accountIds || !accountIds.length - ? of([] as Vote[]) - : api.query.democracy.voteOf.multi( - accountIds.map((accountId): [BN, AccountId] => - [referendumId, accountId] - ) + return memo((referendumId: BN, accountIds: AccountId[] = []): Observable => + !accountIds || !accountIds.length + ? of([] as Vote[]) + : api.query.democracy.voteOf.multi( + accountIds.map((accountId): [BN, AccountId] => + [referendumId, accountId] ) - ).pipe(drr()); + ) + ); } diff --git a/packages/api-derive/src/elections/approvalsOf.ts b/packages/api-derive/src/elections/approvalsOf.ts index 8893438d53..6bb120389d 100644 --- a/packages/api-derive/src/elections/approvalsOf.ts +++ b/packages/api-derive/src/elections/approvalsOf.ts @@ -9,7 +9,7 @@ import { Observable } from 'rxjs'; import { Vec } from '@polkadot/types'; import { switchMap, map } from 'rxjs/operators'; import { approvalFlagsToBools } from '../util/approvalFlagsToBools'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name approvalsOf @@ -24,7 +24,7 @@ import { drr } from '../util'; * ``` */ export function approvalsOf (api: ApiInterfaceRx): (who: AccountId) => Observable { - return (who: AccountId | string): Observable => + return memo((who: AccountId | string): Observable => api.query.elections.nextVoterSet().pipe( switchMap((nextVoterSet: SetIndex): Observable[]> => api.query.elections.approvalsOf.multi( @@ -37,7 +37,6 @@ export function approvalsOf (api: ApiInterfaceRx): (who: AccountId) => Observabl votes.map((flags: Vec): boolean[] => approvalFlagsToBools(flags) ) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/elections/approvalsOfAt.ts b/packages/api-derive/src/elections/approvalsOfAt.ts index ec4021f1e7..6dbb6c50fc 100644 --- a/packages/api-derive/src/elections/approvalsOfAt.ts +++ b/packages/api-derive/src/elections/approvalsOfAt.ts @@ -11,7 +11,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { Vec } from '@polkadot/types'; import { approvalFlagsToBools } from '../util/approvalFlagsToBools'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name approvalsOfAt @@ -26,9 +26,8 @@ import { drr } from '../util'; * ``` */ export function approvalsOfAt (api: ApiInterfaceRx): (who: AccountId, at: SetIndex) => Observable { - return (who: AccountId | string, at: SetIndex | BN | number): Observable => + return memo((who: AccountId | string, at: SetIndex | BN | number): Observable => api.query.elections.approvalsOf>([who.toString(), at]).pipe( - map((flags: Vec): boolean[] => approvalFlagsToBools(flags)), - drr() - ); + map((flags: Vec): boolean[] => approvalFlagsToBools(flags)) + )); } diff --git a/packages/api-derive/src/elections/info.ts b/packages/api-derive/src/elections/info.ts index 42a1455f18..84f69c7d46 100644 --- a/packages/api-derive/src/elections/info.ts +++ b/packages/api-derive/src/elections/info.ts @@ -11,7 +11,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { createType, Vec, u32 } from '@polkadot/types'; import { DerivedElectionsInfo } from '../types'; -import { drr } from '../util'; +import { memo } from '../util'; type ResultElectionsInner = [u32, u32, Vec<[AccountId, BlockNumber] & Codec>, SetIndex, BlockNumber, VoteIndex, SetIndex]; type ResultElections = [Vec, ResultElectionsInner]; @@ -97,6 +97,6 @@ export function info (api: ApiInterfaceRx): () => Observable => - query(api).pipe(drr()); + return memo((): Observable => + query(api)); } diff --git a/packages/api-derive/src/elections/voterPositions.ts b/packages/api-derive/src/elections/voterPositions.ts index d424964534..8861d86654 100644 --- a/packages/api-derive/src/elections/voterPositions.ts +++ b/packages/api-derive/src/elections/voterPositions.ts @@ -11,7 +11,7 @@ import BN from 'bn.js'; import { of, combineLatest, Observable } from 'rxjs'; import { switchMap, map } from 'rxjs/operators'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @name voterPositions @@ -27,7 +27,7 @@ import { drr } from '../util'; * ``` */ export function voterPositions (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => api.query.elections.nextVoterSet().pipe( switchMap((nextVoterSet: SetIndex): Observable<[BN, Vec>[]]> => combineLatest( of(api.consts.elections.voterSetSize) as any as Observable, @@ -53,7 +53,6 @@ export function voterPositions (api: ApiInterfaceRx): () => Observable Observable> { - return (): Observable> => + return memo((): Observable> => api.derive.elections.voterPositions().pipe( map((voterPositions: DerivedVoterPositions): Vec => createType( @@ -34,7 +34,6 @@ export function voters (api: ApiInterfaceRx): () => Observable> { .sort((a, b): number => a[1].globalIndex.cmp(b[1].globalIndex)) .map(([accountId]): AccountId => createType('AccountId', accountId)) ) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/imOnline/receivedHeartbeats.ts b/packages/api-derive/src/imOnline/receivedHeartbeats.ts index 00494c0faa..6a5a7c4abc 100644 --- a/packages/api-derive/src/imOnline/receivedHeartbeats.ts +++ b/packages/api-derive/src/imOnline/receivedHeartbeats.ts @@ -10,13 +10,13 @@ import { map, switchMap } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { Bytes, Option, u32 } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @description Return a boolean array indicating whether the passed accounts had received heartbeats in the current session */ export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => api.query.imOnline?.receivedHeartbeats && api.query.imOnline.authoredBlocks ? api.derive.staking.overview().pipe( switchMap(({ currentIndex, validators }): Observable<[AccountId[], Option[], u32[]]> => @@ -35,8 +35,7 @@ export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable Observable { - return (): Observable => + return memo((): Observable => api.derive.session.info().pipe( - map(({ eraLength }: DerivedSessionInfo): BlockNumber => eraLength), - drr() - ); + map(({ eraLength }: DerivedSessionInfo): BlockNumber => eraLength) + )); } diff --git a/packages/api-derive/src/session/eraProgress.ts b/packages/api-derive/src/session/eraProgress.ts index 760123ee9f..a27193c3d0 100644 --- a/packages/api-derive/src/session/eraProgress.ts +++ b/packages/api-derive/src/session/eraProgress.ts @@ -9,12 +9,11 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { drr } from '../util'; +import { memo } from '../util'; export function eraProgress (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => api.derive.session.info().pipe( - map(({ eraProgress }: DerivedSessionInfo): BlockNumber => eraProgress), - drr() - ); + map(({ eraProgress }: DerivedSessionInfo): BlockNumber => eraProgress) + )); } diff --git a/packages/api-derive/src/session/indexes.ts b/packages/api-derive/src/session/indexes.ts index a1150a2661..d710a2a77a 100644 --- a/packages/api-derive/src/session/indexes.ts +++ b/packages/api-derive/src/session/indexes.ts @@ -10,10 +10,10 @@ import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { createType, u32 as U32 } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; export function indexes (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => ( // Some chains (eg. very limited node-template), does not have session api.query.session && api.query.staking @@ -26,7 +26,6 @@ export function indexes (api: ApiInterfaceRx): () => Observable ({ currentIndex, currentEra, validatorCount - })), - drr() - ); + })) + )); } diff --git a/packages/api-derive/src/session/info.ts b/packages/api-derive/src/session/info.ts index cbdbdc9e1d..c5b21e1610 100644 --- a/packages/api-derive/src/session/info.ts +++ b/packages/api-derive/src/session/info.ts @@ -10,7 +10,7 @@ import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { Option, u64, createType } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; type ResultV1Session = [Option, BlockNumber, BlockNumber, SessionIndex]; type ResultV1 = [BlockNumber, DeriveSessionIndexes, ResultV1Session]; @@ -127,6 +127,6 @@ export function info (api: ApiInterfaceRx): () => Observable : infoLatestAura // 2.x with Aura (not all info there) : infoV1; - return (): Observable => - query(api).pipe(drr()); + return memo((): Observable => + query(api)); } diff --git a/packages/api-derive/src/session/sessionProgress.ts b/packages/api-derive/src/session/sessionProgress.ts index 88e27b80d4..80112375e4 100644 --- a/packages/api-derive/src/session/sessionProgress.ts +++ b/packages/api-derive/src/session/sessionProgress.ts @@ -9,12 +9,11 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { drr } from '../util'; +import { memo } from '../util'; export function sessionProgress (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => api.derive.session.info().pipe( - map(({ sessionProgress }: DerivedSessionInfo): BlockNumber => sessionProgress), - drr() - ); + map(({ sessionProgress }: DerivedSessionInfo): BlockNumber => sessionProgress) + )); } diff --git a/packages/api-derive/src/staking/controllers.ts b/packages/api-derive/src/staking/controllers.ts index 438c0edcea..63bb63f1c2 100644 --- a/packages/api-derive/src/staking/controllers.ts +++ b/packages/api-derive/src/staking/controllers.ts @@ -10,13 +10,13 @@ import { Observable, combineLatest, of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { Option } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @description From the list of stash accounts, retrieve the list of controllers */ export function controllers (api: ApiInterfaceRx): () => Observable<[AccountId[], Option[]]> { - return (): Observable<[AccountId[], Option[]]> => + return memo((): Observable<[AccountId[], Option[]]> => api.query.staking.validators<[AccountId[]] & Codec>().pipe( switchMap(([stashIds]): Observable<[AccountId[], Option[]]> => combineLatest([ @@ -26,7 +26,6 @@ export function controllers (api: ApiInterfaceRx): () => Observable<[AccountId[] ? of([]) : api.query.staking.bonded.multi>(stashIds) ]) - ), - drr() - ); + ) + )); } diff --git a/packages/api-derive/src/staking/info.ts b/packages/api-derive/src/staking/info.ts index d084284c79..1e85208962 100644 --- a/packages/api-derive/src/staking/info.ts +++ b/packages/api-derive/src/staking/info.ts @@ -3,7 +3,7 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { AccountId, Balance, BlockNumber, Exposure, Keys, RewardDestination, StakingLedger, UnlockChunk, ValidatorPrefs } from '@polkadot/types/interfaces'; -import { Codec } from '@polkadot/types/types'; +import { ITuple } from '@polkadot/types/types'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { DerivedRecentlyOffline, DerivedStaking, DerivedUnlocking } from '../types'; @@ -15,7 +15,7 @@ import { createType, Option, Vec } from '@polkadot/types'; import { isUndefined } from '@polkadot/util'; -import { drr } from '../util'; +import { memo } from '../util'; interface ParseInput { accountId: AccountId; @@ -136,7 +136,7 @@ function parseResult ({ accountId, controllerId, stashId, eraLength, bestNumber, }; } -type MultiResultV1 = [Option, Option, [Vec], RewardDestination, Exposure, [ValidatorPrefs] & Codec]; +type MultiResultV1 = [Option, Option, [Vec], RewardDestination, Exposure, ITuple<[ValidatorPrefs]>]; function retrieveInfoV1 (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable { return combineLatest([ @@ -167,7 +167,7 @@ function retrieveInfoV2 (api: ApiInterfaceRx, accountId: AccountId, stashId: Acc return combineLatest([ api.derive.chain.bestNumber(), api.derive.session.eraLength(), - api.query.session.queuedKeys>(), + api.query.session.queuedKeys>>(), api.queryMulti([ [api.query.staking.ledger, controllerId], [api.query.staking.nominators, stashId], @@ -218,6 +218,6 @@ export function info (api: ApiInterfaceRx): (_accountId: Uint8Array | string) => ? retrieveV2 : retrieveV1; - return (accountId: Uint8Array | string): Observable => - query(api, createType('AccountId', accountId)).pipe(drr()); + return memo((accountId: Uint8Array | string): Observable => + query(api, createType('AccountId', accountId))); } diff --git a/packages/api-derive/src/staking/infoStash.ts b/packages/api-derive/src/staking/infoStash.ts index eb3fe1eeaf..4545d0b6cc 100644 --- a/packages/api-derive/src/staking/infoStash.ts +++ b/packages/api-derive/src/staking/infoStash.ts @@ -11,7 +11,7 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { Option, Vec } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; // NOTE Unused ATM, preparing for V2-only @@ -57,9 +57,8 @@ export function infoStash (api: ApiInterfaceRx): (stashId: AccountId) => Observa ? retrieveV2 : retrieveV1; - return (stashId: AccountId): Observable => + return memo((stashId: AccountId): Observable => query(api, stashId).pipe( - map((result): DerivedStakingStash => parse(stashId, result)), - drr() - ); + map((result): DerivedStakingStash => parse(stashId, result)) + )); } diff --git a/packages/api-derive/src/staking/overview.ts b/packages/api-derive/src/staking/overview.ts index 08a5352c80..877d67e350 100644 --- a/packages/api-derive/src/staking/overview.ts +++ b/packages/api-derive/src/staking/overview.ts @@ -10,13 +10,13 @@ import { Observable, combineLatest, of } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; import { createType } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @description Retrieve the staking overview, including elected and points earned */ export function overview (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => combineLatest([ api.derive.session.indexes(), api.derive.staking.validators() @@ -32,7 +32,6 @@ export function overview (api: ApiInterfaceRx): () => Observable ({ currentElected, currentEra, currentIndex, eraPoints, validators, validatorCount - })), - drr() - ); + })) + )); } diff --git a/packages/api-derive/src/staking/recentlyOffline.ts b/packages/api-derive/src/staking/recentlyOffline.ts index 6abc74f039..73ae32433c 100644 --- a/packages/api-derive/src/staking/recentlyOffline.ts +++ b/packages/api-derive/src/staking/recentlyOffline.ts @@ -11,7 +11,7 @@ import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { DerivedRecentlyOffline } from '../types'; -import { drr } from '../util'; +import { memo } from '../util'; type OfflineResult = [AccountId, BlockNumber, BN][] & Codec; @@ -36,7 +36,7 @@ function expandDerived (recentlyOffline: OfflineResult): DerivedRecentlyOffline * @description Retrieve a keyed record of accounts recently reported to be offline */ export function recentlyOffline (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => ( // TODO recentlyOffline has been dropped for 2.x and replaced, figure out the // replacement as actually use and implement it @@ -44,7 +44,6 @@ export function recentlyOffline (api: ApiInterfaceRx): () => Observable() : of([] as unknown as OfflineResult) ).pipe( - map(expandDerived), - drr() - ); + map(expandDerived) + )); } diff --git a/packages/api-derive/src/staking/validators.ts b/packages/api-derive/src/staking/validators.ts index 6c2d0e3c2a..5bed2dcd6a 100644 --- a/packages/api-derive/src/staking/validators.ts +++ b/packages/api-derive/src/staking/validators.ts @@ -10,13 +10,13 @@ import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { Vec } from '@polkadot/types'; -import { drr } from '../util'; +import { memo } from '../util'; /** * @description Retrieve latest list of validators */ export function validators (api: ApiInterfaceRx): () => Observable { - return (): Observable => + return memo((): Observable => ( // Sadly the node-template is (for some obscure reason) not comprehensive, so while the derive works // in all actual real-world deployed chains, it does create some confusion for limited template chains @@ -29,7 +29,6 @@ export function validators (api: ApiInterfaceRx): () => Observable ({ currentElected, validators - })), - drr() - ); + })) + )); } diff --git a/packages/api-derive/src/util/drr.ts b/packages/api-derive/src/util/drr.ts deleted file mode 100644 index 593f026957..0000000000 --- a/packages/api-derive/src/util/drr.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2017-2019 @polkadot/api-derive 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 { drr as drrBase, DrrResult } from '@polkadot/rpc-core/rxjs'; - -export const drr = (): DrrResult => - drrBase({ skipTimeout: true }); diff --git a/packages/api-derive/src/util/index.ts b/packages/api-derive/src/util/index.ts index 66567da6ee..5726cf46ae 100644 --- a/packages/api-derive/src/util/index.ts +++ b/packages/api-derive/src/util/index.ts @@ -3,5 +3,4 @@ // of the Apache-2.0 license. See the LICENSE file for details. export * from './approvalFlagsToBools'; -export * from './drr'; export * from './memo'; diff --git a/packages/api-derive/src/util/memo.ts b/packages/api-derive/src/util/memo.ts index 1499fb3fb2..db4950747e 100644 --- a/packages/api-derive/src/util/memo.ts +++ b/packages/api-derive/src/util/memo.ts @@ -3,12 +3,31 @@ // of the Apache-2.0 license. See the LICENSE file for details.v import createMemo from 'memoizee'; +import { Observable, Observer } from 'rxjs'; +import { drr } from '@polkadot/rpc-core/rxjs'; -export function memo (fn: T, withoutJSON?: boolean): T { - return withoutJSON - ? createMemo(fn) - : createMemo(fn, { - // eslint-disable-next-line @typescript-eslint/unbound-method - normalizer: JSON.stringify - }); +type ObsFn = (...params: any[]) => Observable; + +// Normalize via JSON.stringify, allow e.g. AccountId -> ss58 +// eslint-disable-next-line @typescript-eslint/unbound-method +const normalizer = JSON.stringify; + +// Wraps a derive, doing 2 things to optimize calls - +// 1. creates a memo of the inner fn -> Observable, removing when unsubscribed +// 2. wraps the observable in a drr() (which includes an unsub delay) +export function memo (inner: ObsFn): ObsFn { + const cached = createMemo( + (...params: any[]): Observable => + Observable.create((observer: Observer): VoidCallback => { + const sub = inner(...params).subscribe(observer); + + return (): void => { + cached.delete(...params); + sub.unsubscribe(); + }; + }).pipe(drr()), + { normalizer } + ); + + return cached; }