diff --git a/packages/api-derive/src/accounts/idAndIndex.ts b/packages/api-derive/src/accounts/idAndIndex.ts index 5e989f30fe..8ea3d74d57 100644 --- a/packages/api-derive/src/accounts/idAndIndex.ts +++ b/packages/api-derive/src/accounts/idAndIndex.ts @@ -30,6 +30,9 @@ export type AccountIdAndIndex = [AccountId?, AccountIndex?]; * ``` */ export function idAndIndex (api: ApiInterfaceRx): (address?: Address | AccountId | AccountIndex | string | null) => Observable { + const idToIndexCall = idToIndex(api); + const indexToIdCall = indexToId(api); + return (address?: Address | AccountId | AccountIndex | string | null): Observable => { try { // yes, this can fail, don't care too much, catch will catch it @@ -40,7 +43,7 @@ export function idAndIndex (api: ApiInterfaceRx): (address?: Address | AccountId if (decoded.length === 32) { const accountId = createType('AccountId', decoded); - return idToIndex(api)(accountId).pipe( + return idToIndexCall(accountId).pipe( startWith(undefined), map((accountIndex): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex), drr() @@ -49,7 +52,7 @@ export function idAndIndex (api: ApiInterfaceRx): (address?: Address | AccountId const accountIndex = createType('AccountIndex', decoded); - return indexToId(api)(accountIndex).pipe( + return indexToIdCall(accountIndex).pipe( startWith(undefined), map((accountId): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex), drr() diff --git a/packages/api-derive/src/accounts/idToIndex.ts b/packages/api-derive/src/accounts/idToIndex.ts index 84f6470b12..52a2a0ac6e 100644 --- a/packages/api-derive/src/accounts/idToIndex.ts +++ b/packages/api-derive/src/accounts/idToIndex.ts @@ -26,8 +26,10 @@ import { drr } from '../util/drr'; * ``` */ export function idToIndex (api: ApiInterfaceRx): (accountId: AccountId | string) => Observable { + const indexesCall = indexes(api); + return (accountId: AccountId | string): Observable => - indexes(api)().pipe( + indexesCall().pipe( startWith({}), map((indexes: AccountIndexes): AccountIndex | undefined => (indexes || {})[accountId.toString()] diff --git a/packages/api-derive/src/balances/all.ts b/packages/api-derive/src/balances/all.ts index 5f9861f0e2..0651722fcc 100644 --- a/packages/api-derive/src/balances/all.ts +++ b/packages/api-derive/src/balances/all.ts @@ -83,13 +83,16 @@ function queryBalances (api: ApiInterfaceRx, accountId: AccountId): Observable Observable { + const bestNumberCall = bestNumber(api); + const idAndIndexCall = idAndIndex(api); + return (address: AccountIndex | AccountId | Address | string): Observable => { - return idAndIndex(api)(address).pipe( + return idAndIndexCall(address).pipe( switchMap(([accountId]): Observable => (accountId ? combineLatest([ of(accountId), - bestNumber(api)(), + bestNumberCall(), queryBalances(api, accountId), // FIXME This is having issues with Kusama, only use accountNonce atm // api.rpc.account && api.rpc.account.nextIndex diff --git a/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts b/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts index 862a22dced..85743dec4b 100644 --- a/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts +++ b/packages/api-derive/src/balances/votingBalancesNominatorsFor.ts @@ -15,8 +15,10 @@ import { drr } from '../util/drr'; import { votingBalances } from './votingBalances'; export function votingBalancesNominatorsFor (api: ApiInterfaceRx): (address: AccountId | AccountIndex | Address | string) => Observable { + const idAndIndexCall = idAndIndex(api); + return (address: AccountId | AccountIndex | Address | string): Observable => { - return idAndIndex(api)(address).pipe( + return idAndIndexCall(address).pipe( switchMap(([accountId]): Observable => accountId ? (api.query.staking.nominatorsFor>(accountId)) diff --git a/packages/api-derive/src/chain/bestNumberLag.ts b/packages/api-derive/src/chain/bestNumberLag.ts index c36f66d32d..e808dc4157 100644 --- a/packages/api-derive/src/chain/bestNumberLag.ts +++ b/packages/api-derive/src/chain/bestNumberLag.ts @@ -27,10 +27,13 @@ import { bestNumberFinalized } from './bestNumberFinalized'; * ``` */ export function bestNumberLag (api: ApiInterfaceRx): () => Observable { + const bestNumberCall = bestNumber(api); + const bestNumberFinalizedCall = bestNumberFinalized(api); + return (): Observable => combineLatest([ - bestNumber(api)(), - bestNumberFinalized(api)() + bestNumberCall(), + bestNumberFinalizedCall() ]).pipe( map(([bestNumber, bestNumberFinalized]): BlockNumber => createType('BlockNumber', bestNumber.sub(bestNumberFinalized)) diff --git a/packages/api-derive/src/democracy/referendumVotesFor.ts b/packages/api-derive/src/democracy/referendumVotesFor.ts index bfd3b6d74d..d3a5fc4964 100644 --- a/packages/api-derive/src/democracy/referendumVotesFor.ts +++ b/packages/api-derive/src/democracy/referendumVotesFor.ts @@ -16,13 +16,16 @@ import { votes } from './votes'; import { votingBalances } from '../balances/votingBalances'; export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | number) => Observable { + const votesCall = votes(api); + const votingBalancesCall = votingBalances(api); + return (referendumId: BN | number): Observable => (api.query.democracy.votersFor>(referendumId)).pipe( switchMap((votersFor): Observable<[Vec, Vote[], DerivedBalances[]]> => combineLatest([ of(votersFor), - votes(api)(referendumId as BN, votersFor), - votingBalances(api)(votersFor) + votesCall(referendumId as BN, votersFor), + votingBalancesCall(votersFor) ]) ), map(([votersFor, votes, balances]): DerivedReferendumVote[] => diff --git a/packages/api-derive/src/democracy/referendums.ts b/packages/api-derive/src/democracy/referendums.ts index a8a03f1367..c40d138425 100644 --- a/packages/api-derive/src/democracy/referendums.ts +++ b/packages/api-derive/src/democracy/referendums.ts @@ -15,6 +15,8 @@ import { drr } from '../util/drr'; import { referendumInfos } from './referendumInfos'; export function referendums (api: ApiInterfaceRx): () => Observable[]> { + const referendumInfosCall = referendumInfos(api); + return (): Observable[]> => (api.queryMulti([ api.query.democracy.nextTally, @@ -22,7 +24,7 @@ export function referendums (api: ApiInterfaceRx): () => Observable).pipe( switchMap(([nextTally, referendumCount]): Observable[]> => referendumCount && nextTally && referendumCount.gt(nextTally) && referendumCount.gtn(0) - ? referendumInfos(api)( + ? referendumInfosCall( [...Array(referendumCount.sub(nextTally).toNumber())].map((_, i): BN => nextTally.addn(i) ) diff --git a/packages/api-derive/src/elections/info.ts b/packages/api-derive/src/elections/info.ts index e726435539..c035a2f763 100644 --- a/packages/api-derive/src/elections/info.ts +++ b/packages/api-derive/src/elections/info.ts @@ -58,7 +58,8 @@ function derivePhragmen (candidates: Vec, members: Vec<[AccountId, Ba } function queryPhragmen (api: ApiInterfaceRx): Observable { - // NOTE We have an issue where candidates can return `null` for an empty array + // 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.electionsPhragmen.candidates>(), api.query.electionsPhragmen.members>() diff --git a/packages/api-derive/src/elections/voters.ts b/packages/api-derive/src/elections/voters.ts index 914fe62be0..73ddf1de29 100644 --- a/packages/api-derive/src/elections/voters.ts +++ b/packages/api-derive/src/elections/voters.ts @@ -26,8 +26,10 @@ import { voterPositions } from './voterPositions'; * ``` */ export function voters (api: ApiInterfaceRx): () => Observable> { + const voterPositionsCall = voterPositions(api); + return (): Observable> => - voterPositions(api)().pipe( + voterPositionsCall().pipe( map( (voterPositions: DerivedVoterPositions): Vec => createType( diff --git a/packages/api-derive/src/session/eraLength.ts b/packages/api-derive/src/session/eraLength.ts index 5ef8d68150..0e68eb0106 100644 --- a/packages/api-derive/src/session/eraLength.ts +++ b/packages/api-derive/src/session/eraLength.ts @@ -2,7 +2,8 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import BN from 'bn.js'; +import { BlockNumber } from '@polkadot/types/interfaces'; + import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ApiInterfaceRx } from '@polkadot/api/types'; @@ -10,10 +11,12 @@ import { ApiInterfaceRx } from '@polkadot/api/types'; import { drr } from '../util/drr'; import { info } from './info'; -export function eraLength (api: ApiInterfaceRx): () => Observable { - return (): Observable => - info(api)().pipe( - map(({ eraLength }): BN => eraLength), +export function eraLength (api: ApiInterfaceRx): () => Observable { + const infoCall = info(api); + + return (): Observable => + infoCall().pipe( + map(({ eraLength }): BlockNumber => eraLength), drr() ); } diff --git a/packages/api-derive/src/session/eraProgress.ts b/packages/api-derive/src/session/eraProgress.ts index 7ddd070daf..3831d5b626 100644 --- a/packages/api-derive/src/session/eraProgress.ts +++ b/packages/api-derive/src/session/eraProgress.ts @@ -11,8 +11,10 @@ import { drr } from '../util/drr'; import { info } from './info'; export function eraProgress (api: ApiInterfaceRx): () => Observable { + const infoCall = info(api); + return (): Observable => - info(api)().pipe( + infoCall().pipe( map(({ eraProgress }): BN => eraProgress), drr() ); diff --git a/packages/api-derive/src/session/info.ts b/packages/api-derive/src/session/info.ts index 54698d9473..3241df8d0b 100644 --- a/packages/api-derive/src/session/info.ts +++ b/packages/api-derive/src/session/info.ts @@ -13,8 +13,8 @@ import { Option, u64, createType } from '@polkadot/types'; import { drr } from '../util/drr'; import { bestNumber } from '../chain'; -type Result94Session = [SessionIndex, Option, BlockNumber, BlockNumber, SessionIndex]; -type Result94 = [BlockNumber, Result94Session]; +type ResultV1Session = [SessionIndex, Option, BlockNumber, BlockNumber, SessionIndex]; +type ResultV1 = [BlockNumber, ResultV1Session]; type ResultIndex = [SessionIndex, EraIndex]; type ResultSlots = [u64, u64, u64, SessionIndex, EraIndex, SessionIndex]; @@ -22,7 +22,7 @@ type ResultType = [boolean, u64, SessionIndex]; type Result = [ResultType, ResultSlots]; // internal helper to just split the logic - take all inputs, do the calculations and combine -function createDerived94 ([bestNumber, [currentIndex, _lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: Result94): DerivedSessionInfo { +function createDerivedV1 ([bestNumber, [currentIndex, _lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: ResultV1): DerivedSessionInfo { const lastLengthChange = (_lastLengthChange && _lastLengthChange.unwrapOr(null)) || createType('BlockNumber'); const sessionProgress = bestNumber .sub(lastLengthChange) @@ -68,10 +68,10 @@ function createDerivedLatest ([[hasBabe, epochDuration, sessionsPerEra], [curren }; } -function info94 (api: ApiInterfaceRx): Observable { +function infoV1 (api: ApiInterfaceRx, bestNumberCall: () => Observable): Observable { return combineLatest([ - bestNumber(api)(), - api.queryMulti([ + bestNumberCall(), + api.queryMulti([ api.query.session.currentIndex, api.query.session.lastLengthChange, api.query.session.sessionLength, @@ -79,7 +79,7 @@ function info94 (api: ApiInterfaceRx): Observable { api.query.staking.sessionsPerEra ]) ]).pipe( - map(createDerived94), + map(createDerivedV1), drr() ); } @@ -122,14 +122,13 @@ function infoLatestBabe (api: ApiInterfaceRx): Observable { * @description Retrieves all the session and era info and calculates specific values on it as the length of the session and eras */ export function info (api: ApiInterfaceRx): () => Observable { + const bestNumberCall = bestNumber(api); + return (): Observable => { - // With substrate `spec_version 94`, the era and session has been explicitly exposed as `parameter_types`. - // pre-94 we had more info and needed to calculate (handle old/Alex first) - // https://github.com/paritytech/substrate/commit/dbf322620948935d2bbae214504e6c668c3073ed#diff-c29f42d6b931fa93ba038dbbbfec3055 - return api.query.session.lastLengthChange - ? info94(api) // 1.x - : api.consts.babe + return api.consts.staking + ? api.consts.babe ? infoLatestBabe(api) // 2.x with Babe - : infoLatestAura(api); // 2.x with Aura (not all info there) + : infoLatestAura(api) // 2.x with Aura (not all info there) + : infoV1(api, bestNumberCall); // 1.x }; } diff --git a/packages/api-derive/src/session/sessionProgress.ts b/packages/api-derive/src/session/sessionProgress.ts index b8f4f66b74..f33344a574 100644 --- a/packages/api-derive/src/session/sessionProgress.ts +++ b/packages/api-derive/src/session/sessionProgress.ts @@ -12,8 +12,10 @@ import { drr } from '../util/drr'; import { info } from './info'; export function sessionProgress (api: ApiInterfaceRx): () => Observable { + const infoCall = info(api); + return (): Observable => - info(api)().pipe( + infoCall().pipe( map(({ sessionProgress }): BlockNumber => sessionProgress), drr() ); diff --git a/packages/api-derive/src/staking/all.ts b/packages/api-derive/src/staking/all.ts new file mode 100644 index 0000000000..93a85d6c77 --- /dev/null +++ b/packages/api-derive/src/staking/all.ts @@ -0,0 +1,31 @@ +// 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 { DerivedStaking } from '../types'; + +import { Observable, combineLatest } from 'rxjs'; +import { switchMap } from 'rxjs/operators'; +import { ApiInterfaceRx } from '@polkadot/api/types'; + +import { drr } from '../util/drr'; +import { controllers } from './controllers'; +import { info } from './info'; + +/** + * @description Retrieve all the staking info available for the chain + */ +export function all (api: ApiInterfaceRx): () => Observable { + const infoCall = info(api); + const controllersCall = controllers(api); + + return (): Observable => + controllersCall().pipe( + switchMap(([accountIds]): Observable => + combineLatest( + accountIds.map((accountId): Observable => infoCall(accountId)) + ) + ), + drr() + ); +} diff --git a/packages/api-derive/src/staking/index.ts b/packages/api-derive/src/staking/index.ts index 0bbbc12584..7803025a74 100644 --- a/packages/api-derive/src/staking/index.ts +++ b/packages/api-derive/src/staking/index.ts @@ -2,6 +2,7 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +export * from './all'; export * from './controllers'; export * from './info'; export * from './recentlyOffline'; diff --git a/packages/api-derive/src/staking/info.ts b/packages/api-derive/src/staking/info.ts index a3b82a7e36..537a79242c 100644 --- a/packages/api-derive/src/staking/info.ts +++ b/packages/api-derive/src/staking/info.ts @@ -8,7 +8,7 @@ import { Exposure, RewardDestination, StakingLedger, UnlockChunk, ValidatorPrefs import { Codec } from '@polkadot/types/types'; import { ApiInterfaceRx } from '@polkadot/api/types'; -import { DerivedStaking, DerivedUnlocking } from '../types'; +import { DerivedRecentlyOffline, DerivedStaking, DerivedUnlocking } from '../types'; import BN from 'bn.js'; import { combineLatest, Observable, of } from 'rxjs'; @@ -22,7 +22,28 @@ import { eraLength } from '../session/eraLength'; import { recentlyOffline } from './recentlyOffline'; import { drr } from '../util/drr'; -type MultiResult = [Option | Vec<[AccountId, Keys] & Codec>, Option, [AccountId[]], RewardDestination, Exposure, [ValidatorPrefs], Option?]; +interface Calls { + bestNumberCall (): Observable; + eraLengthCall (): Observable; + recentlyOfflineCall (): Observable; +} + +interface ParseInput { + accountId: AccountId; + bestNumber: BlockNumber; + controllerId: AccountId; + eraLength: BlockNumber; + recentlyOffline?: DerivedRecentlyOffline; + nominators: AccountId[]; + rewardDestination: RewardDestination; + queuedKeys?: [AccountId, Keys][]; + stakers: Exposure; + stakingLedger: Option; + stashId: AccountId; + validatorPrefs: ValidatorPrefs; + nextKeys?: Option; + nextKeyFor?: Option; +} // groups the supplied chunks by era, i.e. { [era]: BN(total of values) } function groupByEra (list: UnlockChunk[]): Record { @@ -82,7 +103,7 @@ function redeemableSum (stakingLedger: StakingLedger | undefined, eraLength: BN, }, new BN(0))); } -function unwrapSessionIds (stashId: AccountId, queuedKeys: Option | Vec<[AccountId, Keys] & Codec>, nextKeys: Option): { nextSessionIds: AccountId[]; nextSessionId?: AccountId; sessionIds: AccountId[]; sessionId?: AccountId } { +function unwrapSessionIds (stashId: AccountId, queuedKeys: Option | [AccountId, Keys][], nextKeys: Option): { nextSessionIds: AccountId[]; nextSessionId?: AccountId; sessionIds: AccountId[]; sessionId?: AccountId } { // for 2.x we have a Vec<(ValidatorId,Keys)> of the keys if (Array.isArray(queuedKeys)) { const sessionIds = (queuedKeys.find(([currentId]): boolean => @@ -111,80 +132,116 @@ function unwrapSessionIds (stashId: AccountId, queuedKeys: Option | V }; } -function retrieveMulti (api: ApiInterfaceRx, stashId: AccountId, controllerId: AccountId): Observable { - // A bit horrible, since we push below to forge everything into 1 query - we do this we we end up with one - // query to retrieve everything - const queries: Array = [ - api.query.session.queuedKeys - ? [api.query.session.queuedKeys] - : [api.query.session.nextKeyFor, controllerId], - [api.query.staking.ledger, controllerId], - [api.query.staking.nominators, stashId], - [api.query.staking.payee, stashId], - [api.query.staking.stakers, stashId], - [api.query.staking.validators, stashId] - ]; +function parseResult ({ accountId, controllerId, stashId, eraLength, bestNumber, recentlyOffline = {}, nextKeyFor = createType('Option', null), queuedKeys, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs, nextKeys = createType('Option', null) }: ParseInput): DerivedStaking { + const _stakingLedger = stakingLedger.unwrapOr(undefined); - // - if (api.query.session.nextKeys) { - queries.push([api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]]); - } - - return api.queryMulti(queries) as Observable; + return { + accountId, + controllerId, + nominators, + offline: recentlyOffline[stashId.toString()], + redeemable: redeemableSum(_stakingLedger, eraLength, bestNumber), + rewardDestination, + stakers, + stakingLedger: _stakingLedger, + stashId, + unlocking: calculateUnlocking(_stakingLedger, eraLength, bestNumber), + validatorPrefs, + ...unwrapSessionIds(stashId, queuedKeys || nextKeyFor, nextKeys) + }; } -function retrieveInfo (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable { - return combineLatest([ - eraLength(api)(), - bestNumber(api)(), - recentlyOffline(api)(), - retrieveMulti(api, stashId, controllerId) - ]).pipe( - map(([eraLength, bestNumber, recentlyOffline, [queuedKeys, _stakingLedger, [nominators], rewardDestination, stakers, [validatorPrefs], nextKeys = createType('Option', null)]]): DerivedStaking => { - const stakingLedger = _stakingLedger.unwrapOr(undefined); +type MultiResultV1 = [Option, Option, [Vec], RewardDestination, Exposure, [ValidatorPrefs] & Codec]; - return { - accountId, - controllerId, - nominators, - offline: recentlyOffline[stashId.toString()], - redeemable: redeemableSum(stakingLedger, eraLength, bestNumber), - rewardDestination, - stakers, - stakingLedger, - stashId, - unlocking: calculateUnlocking(stakingLedger, eraLength, bestNumber), - validatorPrefs, - ...unwrapSessionIds(stashId, queuedKeys, nextKeys) - }; +function retrieveInfoV1 (api: ApiInterfaceRx, { bestNumberCall, eraLengthCall, recentlyOfflineCall }: Calls, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable { + return combineLatest([ + bestNumberCall(), + eraLengthCall(), + recentlyOfflineCall(), + api.queryMulti([ + [api.query.session.nextKeyFor, controllerId], + [api.query.staking.ledger, controllerId], + [api.query.staking.nominators, stashId], + [api.query.staking.payee, stashId], + [api.query.staking.stakers, stashId], + [api.query.staking.validators, stashId] + ]) as Observable + ]).pipe(map(([ + bestNumber, eraLength, recentlyOffline, + [nextKeyFor, stakingLedger, [nominators], rewardDestination, stakers, [validatorPrefs]] + ]: [BlockNumber, BlockNumber, DerivedRecentlyOffline, MultiResultV1]): DerivedStaking => + parseResult({ + accountId, controllerId, stashId, eraLength, bestNumber, recentlyOffline, nextKeyFor, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs }) - ); + )); +} + +type MultiResultV2 = [Option, [Vec], RewardDestination, Exposure, [ValidatorPrefs], Option]; + +function retrieveInfoV2 (api: ApiInterfaceRx, { bestNumberCall, eraLengthCall }: Calls, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable { + return combineLatest([ + bestNumberCall(), + eraLengthCall(), + api.query.session.queuedKeys>(), + api.queryMulti([ + [api.query.staking.ledger, controllerId], + [api.query.staking.nominators, stashId], + [api.query.staking.payee, stashId], + [api.query.staking.stakers, stashId], + [api.query.staking.validators, stashId], + [api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]] + ]) as Observable + ]).pipe(map(([ + bestNumber, eraLength, queuedKeys, + [stakingLedger, [nominators], rewardDestination, stakers, [validatorPrefs], nextKeys] + ]: [BlockNumber, BlockNumber, [AccountId, Keys][], MultiResultV2]): DerivedStaking => + parseResult({ + accountId, controllerId, stashId, eraLength, bestNumber, queuedKeys, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs, nextKeys + }) + )); +} + +function retrieveV1 (api: ApiInterfaceRx, calls: Calls, controllerId: AccountId): Observable { + return api.query.staking + .ledger>(controllerId) + .pipe( + switchMap((stakingLedger): Observable => + stakingLedger.isSome + ? retrieveInfoV1(api, calls, controllerId, stakingLedger.unwrap().stash, controllerId) + : of({ accountId: controllerId, nextSessionIds: [], sessionIds: [] }) + ), + drr() + ); +} + +function retrieveV2 (api: ApiInterfaceRx, calls: Calls, stashId: AccountId): Observable { + return api.query.staking + .bonded>(stashId) + .pipe( + switchMap((controllerId): Observable => + controllerId.isSome + ? retrieveInfoV2(api, calls, stashId, stashId, controllerId.unwrap()) + : of({ accountId: stashId, nextSessionIds: [], sessionIds: [] }) + ), + drr() + ); } /** * @description From a stash, retrieve the controllerId and fill in all the relevant staking details */ export function info (api: ApiInterfaceRx): (_accountId: Uint8Array | string) => Observable { + const calls = { + eraLengthCall: eraLength(api), + bestNumberCall: bestNumber(api), + recentlyOfflineCall: recentlyOffline(api) + }; + return (_accountId: Uint8Array | string): Observable => { const accountId = createType('AccountId', _accountId); - return ( - // NOTE For 2.x-only support, only the first path is required, therefore we - // can replace this with `.bonded>(accountId)` - in 2.x - // the session.validators return the stashes (as expected) - api.queryMulti<[Option, Option]>([ - [api.query.staking.bonded, accountId], // try to map to controller - [api.query.staking.ledger, accountId] // try to map to stash (1.x only) - ]) - ).pipe( - switchMap(([controllerId, stakingLedger]): Observable => - controllerId.isSome - ? retrieveInfo(api, accountId, accountId, controllerId.unwrap()) - : stakingLedger.isSome - ? retrieveInfo(api, accountId, stakingLedger.unwrap().stash, accountId) - : of({ accountId, nextSessionIds: [], sessionIds: [] }) - ), - drr() - ); + return api.consts.session + ? retrieveV2(api, calls, accountId) + : retrieveV1(api, calls, accountId); }; } diff --git a/packages/types/src/codec/create/createType.ts b/packages/types/src/codec/create/createType.ts index 7e8c52f4e7..ee00944b16 100644 --- a/packages/types/src/codec/create/createType.ts +++ b/packages/types/src/codec/create/createType.ts @@ -17,13 +17,27 @@ function u8aHasValue (value: Uint8Array): boolean { // With isPedantic, actually check that the encoding matches that supplied. This // is much slower, but verifies that we have the correct types defined function checkInstance (value: Uint8Array, created: FromReg): void { - // For option, we are not adding the initial byte (this is via storage) - const crHex = created.toHex(true); + // the underlying type created.toRawType() + const rawType = created.toRawType(); + + // ignore bytes completely - this is probably a FIXME, since these are somewhat + // breaking for at least online queries - not quite sure wtf is going wrong here + if (rawType === 'Bytes') { + return; + } + + // the hex values for what we have const inHex = u8aToHex(value); + const crHex = created.toHex(); + + // Check equality, based on some different approaches (as decoded) + const isEqual = inHex === crHex || // raw hex values, quick path + inHex === created.toHex(true) || // wrapped options + u8aToHex(value.reverse()) === crHex; // reverse (for numbers, which are BE) // if the hex doesn't match and the value for both is non-empty, complain... bitterly - if (inHex !== crHex && (u8aHasValue(value) || u8aHasValue(created.toU8a(true)))) { - console.warn(`${created.toRawType()}:: Input doesn't match output, received ${inHex}, created ${crHex}`); + if (!isEqual && (u8aHasValue(value) || u8aHasValue(created.toU8a(true)))) { + console.warn(`${rawType}:: Input doesn't match output, received ${u8aToHex(value)}, created ${crHex}`); } }