Aplit derive session.{info, progress} (#2117)

This commit is contained in:
Jaco Greeff
2020-03-30 18:20:34 +02:00
committed by GitHub
parent e69d97619e
commit 5ab0bf3998
8 changed files with 123 additions and 82 deletions
@@ -12,7 +12,7 @@ import { memo } from '../util';
export function eraProgress (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return memo((): Observable<BlockNumber> =>
api.derive.session.info().pipe(
api.derive.session.progress().pipe(
map((info) => info.eraProgress)
));
}
+1
View File
@@ -6,4 +6,5 @@ export * from './eraLength';
export * from './eraProgress';
export * from './indexes';
export * from './info';
export * from './progress';
export * from './sessionProgress';
+17 -58
View File
@@ -5,34 +5,26 @@
import { SessionIndex } from '@polkadot/types/interfaces';
import { DeriveSessionInfo, DeriveSessionIndexes } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, u64 } from '@polkadot/types';
import { u64 } from '@polkadot/types';
import { memo } from '../util';
type ResultSlots = [u64, u64, u64, Option<SessionIndex>];
type ResultSlotsFlat = [u64, u64, u64, SessionIndex];
type ResultType = [boolean, u64, SessionIndex];
type Result = [ResultType, DeriveSessionIndexes, ResultSlotsFlat];
function createDerive (api: ApiInterfaceRx, [[hasBabe, epochDuration, sessionsPerEra], { activeEra, activeEraStart, currentEra, currentIndex, validatorCount }, [currentSlot, epochIndex, epochOrGenesisStartSlot, activeEraStartSessionIndex]]: Result): DeriveSessionInfo {
const epochStartSlot = epochIndex.mul(epochDuration).add(epochOrGenesisStartSlot);
const sessionProgress = currentSlot.sub(epochStartSlot);
const eraProgress = currentIndex.sub(activeEraStartSessionIndex).mul(epochDuration).add(sessionProgress);
type Result = [ResultType, DeriveSessionIndexes];
function createDerive (api: ApiInterfaceRx, [[hasBabe, epochDuration, sessionsPerEra], { activeEra, activeEraStart, currentEra, currentIndex, validatorCount }]: Result): DeriveSessionInfo {
return {
activeEra,
activeEraStart,
currentEra,
currentIndex,
eraLength: api.registry.createType('BlockNumber', sessionsPerEra.mul(epochDuration)),
eraProgress: api.registry.createType('BlockNumber', eraProgress),
isEpoch: hasBabe,
sessionLength: epochDuration,
sessionsPerEra,
sessionProgress: api.registry.createType('BlockNumber', sessionProgress),
validatorCount
};
}
@@ -46,67 +38,34 @@ function queryAura (api: ApiInterfaceRx): Observable<DeriveSessionInfo> {
api.registry.createType('u64', 1),
api.consts.staking?.sessionsPerEra || api.registry.createType('SessionIndex', 1)
],
indexes,
[
api.registry.createType('u64', 1),
api.registry.createType('u64', 1),
api.registry.createType('u64', 1),
api.registry.createType('SessionIndex', 1)
]
indexes
])
)
);
}
function queryBabe (api: ApiInterfaceRx): Observable<[DeriveSessionIndexes, ResultSlotsFlat]> {
function queryBabe (api: ApiInterfaceRx): Observable<DeriveSessionInfo> {
return api.derive.session.indexes().pipe(
switchMap((indexes): Observable<[DeriveSessionIndexes, ResultSlots]> =>
combineLatest([
of(indexes),
api.queryMulti<ResultSlots>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot,
[api.query.staking.erasStartSessionIndex, indexes.activeEra]
])
map((indexes) =>
createDerive(api, [
[
true,
api.consts.babe.epochDuration,
api.consts.staking.sessionsPerEra
],
indexes
])
),
map(([indexes, [currentSlot, epochIndex, genesisSlot, optStartIndex]]): [DeriveSessionIndexes, ResultSlotsFlat] => [
indexes, [currentSlot, epochIndex, genesisSlot, optStartIndex.unwrapOr(api.registry.createType('SessionIndex', 1))]
])
)
);
}
function queryBabeNoHistory (api: ApiInterfaceRx): Observable<[DeriveSessionIndexes, ResultSlotsFlat]> {
return combineLatest([
api.derive.session.indexes(),
api.queryMulti<ResultSlotsFlat>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot,
api.query.staking.currentEraStartSessionIndex
])
]);
}
/**
* @description Retrieves all the session and era query and calculates specific values on it as the length of the session and eras
*/
export function info (api: ApiInterfaceRx): () => Observable<DeriveSessionInfo> {
return memo((): Observable<DeriveSessionInfo> =>
api.consts.babe
? (api.query.staking.erasStartSessionIndex
? queryBabe(api) // 2.x with Babe
: queryBabeNoHistory(api)
).pipe(
map(([indexes, slots]: [DeriveSessionIndexes, ResultSlotsFlat]): DeriveSessionInfo =>
createDerive(api, [
[true, api.consts.babe.epochDuration, api.consts.staking.sessionsPerEra],
indexes,
slots
])
)
)
? queryBabe(api)
: queryAura(api)
);
}
@@ -0,0 +1,90 @@
// Copyright 2017-2020 @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 { SessionIndex } from '@polkadot/types/interfaces';
import { DeriveSessionInfo, DeriveSessionProgress } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, u64 } from '@polkadot/types';
import { memo } from '../util';
type ResultSlots = [u64, u64, u64, Option<SessionIndex>];
type ResultSlotsFlat = [u64, u64, u64, SessionIndex];
function createDerive (api: ApiInterfaceRx, info: DeriveSessionInfo, [currentSlot, epochIndex, epochOrGenesisStartSlot, activeEraStartSessionIndex]: ResultSlotsFlat): DeriveSessionProgress {
const epochStartSlot = epochIndex.mul(info.sessionLength).add(epochOrGenesisStartSlot);
const sessionProgress = currentSlot.sub(epochStartSlot);
const eraProgress = info.currentIndex.sub(activeEraStartSessionIndex).mul(info.sessionLength).add(sessionProgress);
return {
...info,
eraProgress: api.registry.createType('BlockNumber', eraProgress),
sessionProgress: api.registry.createType('BlockNumber', sessionProgress)
};
}
function queryAura (api: ApiInterfaceRx): Observable<DeriveSessionProgress> {
return api.derive.session.info().pipe(
map((info): DeriveSessionProgress =>
createDerive(api, info, [
api.registry.createType('u64', 1),
api.registry.createType('u64', 1),
api.registry.createType('u64', 1),
api.registry.createType('SessionIndex', 1)
])
)
);
}
function queryBabe (api: ApiInterfaceRx): Observable<[DeriveSessionInfo, ResultSlotsFlat]> {
return api.derive.session.info().pipe(
switchMap((info): Observable<[DeriveSessionInfo, ResultSlots]> =>
combineLatest([
of(info),
api.queryMulti<ResultSlots>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot,
[api.query.staking.erasStartSessionIndex, info.activeEra]
])
])
),
map(([info, [currentSlot, epochIndex, genesisSlot, optStartIndex]]): [DeriveSessionInfo, ResultSlotsFlat] => [
info, [currentSlot, epochIndex, genesisSlot, optStartIndex.unwrapOr(api.registry.createType('SessionIndex', 1))]
])
);
}
function queryBabeNoHistory (api: ApiInterfaceRx): Observable<[DeriveSessionInfo, ResultSlotsFlat]> {
return combineLatest([
api.derive.session.info(),
api.queryMulti<ResultSlotsFlat>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot,
api.query.staking.currentEraStartSessionIndex
])
]);
}
/**
* @description Retrieves all the session and era query and calculates specific values on it as the length of the session and eras
*/
export function progress (api: ApiInterfaceRx): () => Observable<DeriveSessionProgress> {
return memo((): Observable<DeriveSessionProgress> =>
api.consts.babe
? (api.query.staking.erasStartSessionIndex
? queryBabe(api) // 2.x with Babe
: queryBabeNoHistory(api)
).pipe(
map(([info, slots]: [DeriveSessionInfo, ResultSlotsFlat]): DeriveSessionProgress =>
createDerive(api, info, slots)
)
)
: queryAura(api)
);
}
@@ -12,7 +12,7 @@ import { memo } from '../util';
export function sessionProgress (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return memo((): Observable<BlockNumber> =>
api.derive.session.info().pipe(
api.derive.session.progress().pipe(
map((info) => info.sessionProgress)
));
}
+4 -1
View File
@@ -16,9 +16,12 @@ export interface DeriveSessionIndexes {
export interface DeriveSessionInfo extends DeriveSessionIndexes {
eraLength: BlockNumber;
eraProgress: BlockNumber;
isEpoch: boolean;
sessionLength: BlockNumber;
sessionsPerEra: SessionIndex;
}
export interface DeriveSessionProgress extends DeriveSessionInfo {
eraProgress: BlockNumber;
sessionProgress: BlockNumber;
}
+5 -19
View File
@@ -3,7 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Balance, BlockNumber, StakingLedger, UnlockChunk } from '@polkadot/types/interfaces';
import { Balance, StakingLedger, UnlockChunk } from '@polkadot/types/interfaces';
import { DeriveSessionInfo, DeriveStakingAccount, DeriveStakingQuery, DeriveUnlocking } from '../types';
import BN from 'bn.js';
@@ -27,27 +27,13 @@ function groupByEra (list: UnlockChunk[]): Record<string, BN> {
}, {});
}
// calculate the remaining blocks in a specific unlock era
function remainingBlocks (api: ApiInterfaceRx, era: BN, sessionInfo: DeriveSessionInfo): BlockNumber {
const remaining = era.sub(sessionInfo.currentEra);
// on the Rust side the current-era >= era-for-unlock (removal done on >)
return api.registry.createType('BlockNumber', remaining.gtn(0)
? remaining
.subn(1)
.mul(sessionInfo.eraLength)
.add(sessionInfo.eraLength.sub(sessionInfo.eraProgress))
: 0
);
}
function calculateUnlocking (api: ApiInterfaceRx, stakingLedger: StakingLedger | undefined, sessionInfo: DeriveSessionInfo): DeriveUnlocking[] | undefined {
if (isUndefined(stakingLedger)) {
return undefined;
}
const unlockingChunks = stakingLedger.unlocking.filter(({ era }): boolean =>
remainingBlocks(api, era.unwrap(), sessionInfo).gtn(0)
era.unwrap().sub(sessionInfo.activeEra).gtn(0)
);
if (!unlockingChunks.length) {
@@ -57,8 +43,8 @@ function calculateUnlocking (api: ApiInterfaceRx, stakingLedger: StakingLedger |
// group the unlock chunks that have the same era and sum their values
const groupedResult = groupByEra(unlockingChunks);
const results = Object.entries(groupedResult).map(([eraString, value]): DeriveUnlocking => ({
value: api.registry.createType('Balance', value),
remainingBlocks: remainingBlocks(api, new BN(eraString), sessionInfo)
remainingEras: new BN(eraString).sub(sessionInfo.activeEra),
value: api.registry.createType('Balance', value)
}));
return results.length ? results : undefined;
@@ -70,7 +56,7 @@ function redeemableSum (api: ApiInterfaceRx, stakingLedger: StakingLedger | unde
}
return api.registry.createType('Balance', stakingLedger.unlocking.reduce((total, { era, value }): BN => {
return remainingBlocks(api, era.unwrap(), sessionInfo).eqn(0)
return sessionInfo.activeEra.gte(era.unwrap())
? total.add(value.unwrap())
: total;
}, new BN(0)));
+4 -2
View File
@@ -2,9 +2,11 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Balance, BlockNumber, EraIndex, EraRewardPoints, Exposure, Keys, RewardDestination, RewardPoint, StakingLedger, ValidatorPrefs } from '@polkadot/types/interfaces';
import { AccountId, Balance, EraIndex, EraRewardPoints, Exposure, Keys, RewardDestination, RewardPoint, StakingLedger, ValidatorPrefs } from '@polkadot/types/interfaces';
import { DeriveSessionIndexes } from '../session/types';
import BN from 'bn.js';
export type DeriveEraValPoints = Record<string, RewardPoint>;
export type DeriveEraValPrefs = Record<string, ValidatorPrefs>;
@@ -119,6 +121,6 @@ export interface DeriveStakingOverview extends DeriveSessionIndexes {
}
export type DeriveUnlocking = {
remainingBlocks: BlockNumber;
remainingEras: BN;
value: Balance;
};