Pass online/offline status indicators with staking accounts (#1265)

* staking online status

* restrict onlineStatus.online to validators

* get onlineStatus for stash/validator only

* tests

* fixes

* Add offline

* Revert stash, change to stashId, linting

* Heartbeat signature

* Make CodeClimate (slightly) happier

* keep compatibility

* change status type

* rv null possible

* cleanup
This commit is contained in:
kwingram25
2019-08-05 16:13:42 +00:00
committed by GitHub
parent 73f33d0168
commit 09ee77d0bc
9 changed files with 125 additions and 11 deletions
@@ -0,0 +1,5 @@
// 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.
export * from './receivedHeartbeats';
@@ -0,0 +1,37 @@
// 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 { AccountId, SessionIndex } from '@polkadot/types/interfaces';
import { of, Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Bytes } from '@polkadot/types';
import { drr } from '../util/drr';
/**
* @description Return a boolean array indicating whether the passed accounts had received heartbeats in the current session
*/
export function receivedHeartbeats (api: ApiInterfaceRx): (addresses: (AccountId | string)[]) => Observable<boolean[]> {
return (addresses: (AccountId | string)[]): Observable<boolean[]> => {
return api.query.imOnline && api.query.imOnline.receivedHeartbeats
? api.query.session
.currentIndex<SessionIndex>()
.pipe(
switchMap((currentIndex): Observable<Bytes[]> =>
api.query.imOnline.receivedHeartbeats.multi(
addresses.map((address): [SessionIndex, AccountId | string] =>
[currentIndex, address]
)
)
),
map((heartbeats): boolean[] =>
heartbeats.map((heartbeat): boolean => !heartbeat.isEmpty)
),
drr()
)
: of([...new Array(addresses.length).keys()].map((): boolean => false));
};
}
+4
View File
@@ -61,6 +61,10 @@ describe('derive', (): void => {
testFunction(api)('session', 'eraLength', []);
testFunction(api)('session', 'eraProgress', []);
testFunction(api)('session', 'sessionProgress', []);
testFunction(api)('staking', 'info', []);
testFunction(api)('staking', 'recentlyOffline', []);
testFunction(api)('staking', 'controllers', []);
});
describe('custom', (): void => {
+2 -1
View File
@@ -13,6 +13,7 @@ import * as chain from './chain';
import * as contracts from './contracts';
import * as democracy from './democracy';
import * as elections from './elections';
import * as imOnline from './imOnline';
import * as session from './session';
import * as staking from './staking';
@@ -56,7 +57,7 @@ function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSect
}, {} as unknown as DeriveSections<AllSections>);
}
export const derive = { accounts, balances, chain, contracts, democracy, elections, session, staking };
export const derive = { accounts, balances, chain, contracts, democracy, elections, imOnline, session, staking };
export type Derive = typeof derive;
// FIXME I have no idea how to get this done
+1
View File
@@ -4,3 +4,4 @@
export * from './controllers';
export * from './info';
export * from './recentlyOffline';
+9 -8
View File
@@ -19,6 +19,7 @@ import { isUndefined } from '@polkadot/util';
import { bestNumber } from '../chain/bestNumber';
import { eraLength } from '../session/eraLength';
import { recentlyOffline } from './recentlyOffline';
import { drr } from '../util/drr';
type MultiResult = [Option<Keys>, [
@@ -128,20 +129,20 @@ function retrieveMulti (api: ApiInterfaceRx, stashId: AccountId, controllerId: A
}
function retrieveInfo (api: ApiInterfaceRx, stashId: AccountId, controllerId: AccountId): Observable<DerivedStaking> {
return (
combineLatest([
eraLength(api)(),
bestNumber(api)(),
retrieveMulti(api, stashId, controllerId)
])
).pipe(
map(([eraLength, bestNumber, [nextKeys, [queuedKeys, _stakingLedger, [nominators], rewardDestination, stakers, [validatorPrefs]]]]): DerivedStaking => {
return combineLatest([
eraLength(api)(),
bestNumber(api)(),
recentlyOffline(api)(),
retrieveMulti(api, stashId, controllerId)
]).pipe(
map(([eraLength, bestNumber, recentlyOffline, [nextKeys, [queuedKeys, _stakingLedger, [nominators], rewardDestination, stakers, [validatorPrefs]]]]): DerivedStaking => {
const stakingLedger = _stakingLedger.unwrapOr(undefined);
return {
accountId: stashId,
controllerId,
nominators,
offline: recentlyOffline[stashId.toString()],
redeemable: redeemableSum(stakingLedger, eraLength, bestNumber),
rewardDestination,
stakers,
@@ -0,0 +1,43 @@
// 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 { AccountId, BlockNumber } from '@polkadot/types/interfaces';
import { Codec } from '@polkadot/types/types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DerivedRecentlyOffline } from '../types';
import { drr } from '../util/drr';
/**
* @description Retrieve a keyed record of accounts recently reported to be offline
*/
export function recentlyOffline (api: ApiInterfaceRx): () => Observable<DerivedRecentlyOffline> {
return (): Observable<DerivedRecentlyOffline> =>
api.query.staking
.recentlyOffline<[AccountId, BlockNumber, BN][] & Codec>()
.pipe(
map((recentlyOffline): DerivedRecentlyOffline =>
recentlyOffline.reduce((result: DerivedRecentlyOffline, [accountId, blockNumber, count]): DerivedRecentlyOffline => {
const key = accountId.toString();
if (!result[key]) {
result[key] = [];
}
result[key].push({
blockNumber,
count
});
return result;
},
{})
),
drr()
);
}
+23 -1
View File
@@ -51,6 +51,13 @@ export interface DerivedFees {
transferFee: BN;
}
export interface RecentlyOffline {
blockNumber: BlockNumber;
count: BN;
}
export type DerivedRecentlyOffline = Record<string, RecentlyOffline[]>;
export interface DerivedReferendumVote {
accountId: AccountId;
balance: Balance;
@@ -70,7 +77,22 @@ export interface DerivedSessionInfo {
sessionProgress: BN;
}
export interface DerivedStaking {
export type DerivedStakingAccount = [AccountId, DerivedStakingOnlineStatus];
export type DerivedStakingAccounts = DerivedStakingAccount[];
export interface DerivedStakingOnlineStatus {
online?: {
isOnline: boolean;
blockNumber?: BlockNumber;
};
offline?: {
blockNumber: BlockNumber;
count: BN;
}[];
}
export interface DerivedStaking extends DerivedStakingOnlineStatus {
accountId: AccountId;
controllerId?: AccountId;
nextSessionId?: AccountId;