diff --git a/packages/api-derive/src/balances/all.ts b/packages/api-derive/src/balances/all.ts index 8dd0f68da7..9466f3a2bf 100644 --- a/packages/api-derive/src/balances/all.ts +++ b/packages/api-derive/src/balances/all.ts @@ -14,10 +14,10 @@ import { bnMax } from '@polkadot/util'; import { memo } from '../util'; -type ResultBalance = [Balance, Balance, BalanceLock[], Option]; -type Result = [AccountId, BlockNumber, ResultBalance, Index]; +type ResultBalance = [Balance, Balance, BalanceLock[], Option, Index]; +type Result = [AccountId, BlockNumber, ResultBalance]; -function calcBalances (api: ApiInterfaceRx, [accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting], accountNonce]: Result): DerivedBalances { +function calcBalances (api: ApiInterfaceRx, [accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting, accountNonce]]: Result): DerivedBalances { let lockedBalance = createType(api.registry, 'Balance'); let lockedBreakdown: BalanceLock[] = []; @@ -64,15 +64,6 @@ function calcBalances (api: ApiInterfaceRx, [accountId, bestNumber, [freeBalance }; } -function queryBalances (api: ApiInterfaceRx, accountId: AccountId): Observable { - return api.queryMulti<[Balance, Balance, Vec, Option]>([ - [api.query.balances.freeBalance, accountId], - [api.query.balances.reservedBalance, accountId], - [api.query.balances.locks, accountId], - [api.query.balances.vesting, accountId] - ]); -} - /** * @name all * @param {( AccountIndex | AccountId | Address | string )} address - An accounts Id in different formats. @@ -96,15 +87,15 @@ export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId | ? combineLatest([ of(accountId), api.derive.chain.bestNumber(), - queryBalances(api, accountId), - // FIXME This is having issues with Kusama, only use accountNonce atm - // api.rpc.account && api.rpc.account.nextIndex - // ? api.rpc.account.nextIndex(accountId) - // // otherwise we end up with this: type 'Codec | Index' is not assignable to type 'Index'. - // : api.query.system.accountNonce(accountId) - api.query.system.accountNonce(accountId) + api.queryMulti<[Balance, Balance, Vec, Option, Index]>([ + [api.query.balances.freeBalance, accountId], + [api.query.balances.reservedBalance, accountId], + [api.query.balances.locks, accountId], + [api.query.balances.vesting, accountId], + [api.query.system.accountNonce, accountId] + ]) ]) - : of([createType(api.registry, 'AccountId'), createType(api.registry, 'BlockNumber'), [createType(api.registry, 'Balance'), createType(api.registry, 'Balance'), createType(api.registry, 'Vec'), createType(api.registry, 'Option', null)], createType(api.registry, 'Index')]) + : of([createType(api.registry, 'AccountId'), createType(api.registry, 'BlockNumber'), [createType(api.registry, 'Balance'), createType(api.registry, 'Balance'), createType(api.registry, 'Vec'), createType(api.registry, 'Option', null), createType(api.registry, 'Index')]]) ) ), map((result): DerivedBalances => calcBalances(api, result)) diff --git a/packages/api-derive/src/collective/proposals.ts b/packages/api-derive/src/collective/proposals.ts index ba9934afc5..3728941df7 100644 --- a/packages/api-derive/src/collective/proposals.ts +++ b/packages/api-derive/src/collective/proposals.ts @@ -4,41 +4,40 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { Hash, Proposal, Votes } from '@polkadot/types/interfaces'; -import { DerivedCollectiveProposals } from '../types'; +import { DerivedCollectiveProposal } from '../types'; import { combineLatest, Observable, of } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; import { Option } from '@polkadot/types'; -export function proposals (api: ApiInterfaceRx, section: 'council' | 'technicalCommittee'): () => Observable { - return (): Observable => - api.query[section] - ? api.query[section].proposals() - .pipe( - switchMap((hashes: Hash[]): Observable<[Hash[], Option[], Option[]]> => { - return combineLatest([ - of(hashes), - combineLatest( - hashes.map((hash): Observable> => api.query[section].proposalOf(hash)) - ), - api.query[section].voting.multi>(hashes) - ]); - }), - map(([hashes, proposals, votes]): DerivedCollectiveProposals => { - const result: DerivedCollectiveProposals = []; +type Result = [Hash[], Option[], Option[]]; - proposals.forEach((proposalOpt, index): void => { - if (proposalOpt.isSome) { - result.push({ +export function proposals (api: ApiInterfaceRx, section: 'council' | 'technicalCommittee'): () => Observable { + return (): Observable => + api.query[section] + ? api.query[section].proposals().pipe( + switchMap((hashes: Hash[]): Observable => + hashes.length + ? combineLatest([ + of(hashes), + api.query[section].proposalOf.multi>(hashes), + api.query[section].voting.multi>(hashes) + ]) + : of([[], [], []]) + ), + map(([hashes, proposals, votes]: Result): DerivedCollectiveProposal[] => + proposals + .map((proposalOpt, index): DerivedCollectiveProposal | null => + proposalOpt.isSome + ? { hash: hashes[index], proposal: proposalOpt.unwrap(), votes: votes[index].unwrapOr(null) - }); - } - }); - - return result; - }) + } + : null + ) + .filter((proposal): boolean => !!proposal) as DerivedCollectiveProposal[] ) - : of([] as DerivedCollectiveProposals); + ) + : of([] as DerivedCollectiveProposal[]); } diff --git a/packages/api-derive/src/democracy/proposals.ts b/packages/api-derive/src/democracy/proposals.ts index f69b0f35f6..3ebd23c5cc 100644 --- a/packages/api-derive/src/democracy/proposals.ts +++ b/packages/api-derive/src/democracy/proposals.ts @@ -64,20 +64,20 @@ function parse (api: ApiInterfaceRx, { depositors, proposals, preimages }: Resul export function proposals (api: ApiInterfaceRx): () => Observable { return memo((): Observable => api.query.democracy?.publicProps - ? api.query.democracy - .publicProps() - .pipe( - switchMap((proposals) => - combineLatest([ - of(proposals), - api.query.democracy.preimages.multi(proposals.map(([, hash]): Hash => hash)), - api.query.democracy.depositOf.multi(proposals.map(([index]): PropIndex => index)) - ]) - ), - map(([proposals, preimages, depositors]): DeriveProposal[] => - parse(api, { depositors, proposals, preimages }) - ) + ? api.query.democracy.publicProps().pipe( + switchMap((proposals) => + combineLatest([ + of(proposals), + api.query.democracy.preimages.multi( + proposals.map(([, hash]): Hash => hash)), + api.query.democracy.depositOf.multi( + proposals.map(([index]): PropIndex => index)) + ]) + ), + map(([proposals, preimages, depositors]): DeriveProposal[] => + parse(api, { depositors, proposals, preimages }) ) + ) : of([] as DeriveProposal[]) ); } diff --git a/packages/api-derive/src/democracy/referendumInfos.ts b/packages/api-derive/src/democracy/referendumInfos.ts index 8a623d502f..5b835aeee9 100644 --- a/packages/api-derive/src/democracy/referendumInfos.ts +++ b/packages/api-derive/src/democracy/referendumInfos.ts @@ -9,7 +9,7 @@ import BN from 'bn.js'; import { Observable, combineLatest, of } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { Option, Vec } from '@polkadot/types'; +import { Option } from '@polkadot/types'; import { memo } from '../util'; import { retrieveInfo } from './referendumInfo'; @@ -17,9 +17,9 @@ import { retrieveInfo } from './referendumInfo'; export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) => Observable { return memo((ids: (BN | number)[] = []): Observable => ( - !ids || !ids.length + !ids?.length ? of([] as Option[]) - : api.query.democracy.referendumInfoOf.multi(ids) as Observable>> + : api.query.democracy.referendumInfoOf.multi>(ids) ).pipe( switchMap((infos): Observable<(DerivedReferendum | null)[]> => combineLatest( diff --git a/packages/api-derive/src/democracy/referendumVotesFor.ts b/packages/api-derive/src/democracy/referendumVotesFor.ts index 59bb0b6ba6..35e7544be1 100644 --- a/packages/api-derive/src/democracy/referendumVotesFor.ts +++ b/packages/api-derive/src/democracy/referendumVotesFor.ts @@ -19,7 +19,7 @@ export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | nu switchMap((votersFor): Observable<[Vec, Vote[], DerivedBalances[]]> => combineLatest([ of(votersFor), - api.derive.democracy.votes(referendumId as BN, votersFor), + api.derive.democracy.votes(referendumId, votersFor), api.derive.balances.votingBalances(votersFor) ]) ), diff --git a/packages/api-derive/src/democracy/votes.ts b/packages/api-derive/src/democracy/votes.ts index 477cd63a7a..5e29633747 100644 --- a/packages/api-derive/src/democracy/votes.ts +++ b/packages/api-derive/src/democracy/votes.ts @@ -10,12 +10,12 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { memo } from '../util'; -export function votes (api: ApiInterfaceRx): (referendumId: BN, accountIds?: AccountId[]) => Observable { - return memo((referendumId: BN, accountIds: AccountId[] = []): Observable => +export function votes (api: ApiInterfaceRx): (referendumId: BN | number, accountIds?: AccountId[]) => Observable { + return memo((referendumId: BN | number, accountIds: AccountId[] = []): Observable => !accountIds || !accountIds.length ? of([] as Vote[]) : api.query.democracy.voteOf.multi( - accountIds.map((accountId): [BN, AccountId] => + accountIds.map((accountId): [BN | number, AccountId] => [referendumId, accountId] ) ) diff --git a/packages/api-derive/src/elections/info.ts b/packages/api-derive/src/elections/info.ts index fc8435db00..45c9ac665c 100644 --- a/packages/api-derive/src/elections/info.ts +++ b/packages/api-derive/src/elections/info.ts @@ -5,7 +5,7 @@ import { AccountId, Balance, BlockNumber } from '@polkadot/types/interfaces'; import { ITuple } from '@polkadot/types/types'; -import { Observable, combineLatest } from 'rxjs'; +import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; import { createType, Vec, u32 } from '@polkadot/types'; @@ -13,39 +13,26 @@ import { createType, Vec, u32 } from '@polkadot/types'; import { DerivedElectionsInfo } from '../types'; import { memo } from '../util'; -function deriveElections (api: ApiInterfaceRx, candidates: AccountId[], members: [AccountId, Balance][], runnersUp: [AccountId, Balance][], candidacyBond: Balance, desiredSeats: u32, termDuration: BlockNumber, votingBond: Balance): DerivedElectionsInfo { - return { - candidates, - candidateCount: createType(api.registry, 'u32', candidates.length), - candidacyBond, - desiredSeats, - members: members.sort((a, b): number => b[1].cmp(a[1])), - runnersUp: runnersUp.sort((a, b): number => b[1].cmp(a[1])), - termDuration, - votingBond - }; -} - function queryElections (api: ApiInterfaceRx): Observable { const section = api.query.electionsPhragmen ? 'electionsPhragmen' : 'elections'; // NOTE We have an issue where candidates can return `null` for an empty array, hence // we are not using multi queries here, so empty array is empty (instead of space-filled) - return combineLatest([ - api.query[section].candidates>(), - api.query[section].members>>(), - api.query[section].runnersUp>>() + return api.queryMulti<[Vec, Vec>, Vec>]>([ + api.query[section].candidates, + api.query[section].members, + api.query[section].runnersUp ]).pipe( - map(([candidates, members, runnersUp]): DerivedElectionsInfo => deriveElections( - api, + map(([candidates, members, runnersUp]): DerivedElectionsInfo => ({ candidates, - members, - runnersUp, - api.consts[section].candidacyBond as Balance, - api.consts[section].desiredMembers as u32, - api.consts[section].termDuration as BlockNumber, - api.consts[section].votingBond as Balance - )) + candidateCount: createType(api.registry, 'u32', candidates.length), + candidacyBond: api.consts[section].candidacyBond as Balance, + desiredSeats: api.consts[section].desiredMembers as u32, + members: members.sort((a, b): number => b[1].cmp(a[1])), + runnersUp: runnersUp.sort((a, b): number => b[1].cmp(a[1])), + termDuration: api.consts[section].termDuration as BlockNumber, + votingBond: api.consts[section].votingBond as Balance + })) ); } diff --git a/packages/api-derive/src/imOnline/receivedHeartbeats.ts b/packages/api-derive/src/imOnline/receivedHeartbeats.ts index 3a926acf26..3be9fc7d6d 100644 --- a/packages/api-derive/src/imOnline/receivedHeartbeats.ts +++ b/packages/api-derive/src/imOnline/receivedHeartbeats.ts @@ -17,13 +17,15 @@ import { memo } from '../util'; */ export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable { return memo((): Observable => - api.query.imOnline?.receivedHeartbeats && api.query.imOnline.authoredBlocks + api.query.imOnline?.receivedHeartbeats ? api.derive.staking.overview().pipe( switchMap(({ currentIndex, validators }): Observable<[AccountId[], Option[], u32[]]> => combineLatest([ of(validators), - api.query.imOnline.receivedHeartbeats.multi>(validators.map((_address, index): [SessionIndex, number] => [currentIndex, index])), - api.query.imOnline.authoredBlocks.multi(validators.map((address): [SessionIndex, AccountId] => [currentIndex, address])) + api.query.imOnline.receivedHeartbeats.multi>( + validators.map((_address, index): [SessionIndex, number] => [currentIndex, index])), + api.query.imOnline.authoredBlocks.multi( + validators.map((address): [SessionIndex, AccountId] => [currentIndex, address])) ]) ), map(([validators, heartbeats, numBlocks]): DerivedHeartbeats => diff --git a/packages/api-derive/src/society/candidates.ts b/packages/api-derive/src/society/candidates.ts index 0a22b3890e..6860ac7289 100644 --- a/packages/api-derive/src/society/candidates.ts +++ b/packages/api-derive/src/society/candidates.ts @@ -3,7 +3,7 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { ApiInterfaceRx } from '@polkadot/api/types'; -import { BalanceOf, Bid, BidKind } from '@polkadot/types/interfaces'; +import { AccountId, BalanceOf, Bid, BidKind } from '@polkadot/types/interfaces'; import { ITuple } from '@polkadot/types/types'; import { DeriveSocietyCandidate } from '../types'; @@ -25,11 +25,8 @@ export function candidates (api: ApiInterfaceRx): () => Observable): Observable => combineLatest([ of(candidates), - combineLatest( - candidates.map(({ who }: Bid): Observable => - api.query.society.suspendedCandidates(who) - ) - ) + api.query.society.suspendedCandidates.multi( + candidates.map(({ who }): AccountId => who)) ]) ), map(([candidates, suspended]: Result): DeriveSocietyCandidate[] => diff --git a/packages/api-derive/src/society/member.ts b/packages/api-derive/src/society/member.ts index af61c10694..86b5cd2927 100644 --- a/packages/api-derive/src/society/member.ts +++ b/packages/api-derive/src/society/member.ts @@ -7,33 +7,27 @@ import { AccountId, Balance, BlockNumber, StrikeCount, VouchingStatus, Vote } fr import { ITuple } from '@polkadot/types/types'; import { DeriveSocietyMember } from '../types'; -import { Observable, combineLatest } from 'rxjs'; +import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { bool, Option, Vec } from '@polkadot/types'; import { memo } from '../util'; -type ResultMulti = [Vec>, StrikeCount]; -type ResultSingle = [Option, bool, Option]; -type Result = [ResultMulti, ResultSingle]; +type Result = [Vec>, StrikeCount, Option, bool, Option]; /** * @description Get the member info for a society */ export function member (api: ApiInterfaceRx): (accountId: AccountId) => Observable { return memo((accountId: AccountId): Observable => - combineLatest([ - api.queryMulti([ - [api.query.society.payouts, accountId], - [api.query.society.strikes, accountId] - ]), - combineLatest([ - api.query.society.defenderVotes>(accountId), - api.query.society.suspendedMembers(accountId), - api.query.society.vouching>(accountId) - ]) + api.queryMulti([ + [api.query.society.payouts, accountId], + [api.query.society.strikes, accountId], + [api.query.society.defenderVotes, accountId], + [api.query.society.suspendedMembers, accountId], + [api.query.society.vouching, accountId] ]).pipe( - map(([[payouts, strikes], [defenderVote, suspended, vouching]]: Result): DeriveSocietyMember => ({ + map(([payouts, strikes, defenderVote, suspended, vouching]: Result): DeriveSocietyMember => ({ accountId, payouts, isSuspended: suspended.isTrue, diff --git a/packages/api-derive/src/staking/overview.ts b/packages/api-derive/src/staking/overview.ts index 0d0dae2ab8..a2174d65c9 100644 --- a/packages/api-derive/src/staking/overview.ts +++ b/packages/api-derive/src/staking/overview.ts @@ -8,7 +8,6 @@ import { DerivedStakingOverview } from '../types'; import { Observable, combineLatest, of } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; -import { createType } from '@polkadot/types'; import { memo } from '../util'; @@ -24,10 +23,7 @@ export function overview (api: ApiInterfaceRx): () => Observable combineLatest([ of({ currentElected, currentEra, currentIndex, validators, validatorCount }), - // this will change on a per block basis, keep it innermost (and it needs eraIndex) - api.query.staking?.currentEraPointsEarned - ? api.query.staking.currentEraPointsEarned(currentEra) - : of(createType(api.registry, 'EraPoints')) + api.query.staking.currentEraPointsEarned(currentEra) ]) ), map(([{ currentElected, currentEra, currentIndex, validators, validatorCount }, eraPoints]): DerivedStakingOverview => ({ diff --git a/packages/api-derive/src/treasury/proposals.ts b/packages/api-derive/src/treasury/proposals.ts index 90f3df1928..baf706cddc 100644 --- a/packages/api-derive/src/treasury/proposals.ts +++ b/packages/api-derive/src/treasury/proposals.ts @@ -62,10 +62,7 @@ function retrieveProposals (api: ApiInterfaceRx, proposalCount: ProposalIndex, a const allIds = [...proposalIds, ...approvalIds]; return combineLatest([ - // We are doing single subscriptions on all these, multi may yield old results - combineLatest( - allIds.map((id): Observable> => api.query.treasury.proposals(id)) - ), + api.query.treasury.proposals.multi>(allIds), api.derive.council.proposals() ]).pipe( map(([allProposals, councilProposals]: [Option[], DerivedCollectiveProposals]): DerivedTreasuryProposals => diff --git a/packages/rpc-core/src/index.ts b/packages/rpc-core/src/index.ts index 6851a48903..e47019fd4f 100644 --- a/packages/rpc-core/src/index.ts +++ b/packages/rpc-core/src/index.ts @@ -16,7 +16,7 @@ import jsonrpcMethod from '@polkadot/jsonrpc/create/method'; import jsonrpcParam from '@polkadot/jsonrpc/create/param'; import { Option, StorageKey, Vec, createClass } from '@polkadot/types'; import { createTypeUnsafe } from '@polkadot/types/codec'; -import { assert, isFunction, isNull, isNumber, logger, u8aToU8a } from '@polkadot/util'; +import { assert, isFunction, isNull, isNumber, isUndefined, logger, u8aToU8a } from '@polkadot/util'; import { drr } from './rxjs'; @@ -390,24 +390,19 @@ export default class Rpc implements RpcInterface { const type = key.outputType || 'Raw'; const hexKey = key.toHex(); const meta = key.meta || EMPTY_META; + const found = changes.find(([key]): boolean => key === hexKey); // if we don't find the value, this is our fallback // - in the case of an array of values, fill the hole from the cache // - if a single result value, don't fill - it is not an update hole // - fallback to an empty option in all cases - const emptyVal = (witCache && this._storageCache.get(hexKey)) || null; - - // see if we have a result value for this specific key, fallback to the cache value - // when the value in the set is not available, or is null/empty. - const [, value] = changes.find(([key, value]): boolean => - !isNull(value) && key === hexKey - ) || [null, emptyVal]; + const value = isUndefined(found) + ? (witCache && this._storageCache.get(hexKey)) || null + : found[1]; const isEmpty = isNull(value); - const input = isEmpty - ? null - : this.treatAsHex(key) - ? value - : u8aToU8a(value); + const input = isEmpty || this.treatAsHex(key) + ? value + : u8aToU8a(value); // store the retrieved result - the only issue with this cache is that there is no // clearing of it, so very long running processes (not just a couple of hours, longer)