Display parachain validators (#4667)

This commit is contained in:
Jaco Greeff 2021-02-15 14:12:52 +01:00 committed by GitHub
parent cb3d879bcf
commit a2fc3e53fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 7 deletions

View File

@ -2,17 +2,18 @@
// SPDX-License-Identifier: Apache-2.0
import type { Option, Vec } from '@polkadot/types';
import type { BlockNumber, HeadData, Header, ParaId } from '@polkadot/types/interfaces';
import type { AccountId, BlockNumber, HeadData, Header, ParaId } from '@polkadot/types/interfaces';
import type { Codec } from '@polkadot/types/types';
import BN from 'bn.js';
import React, { useMemo } from 'react';
import React, { useCallback, useMemo } from 'react';
import { Badge, ParaLink } from '@polkadot/react-components';
import { AddressMini, Badge, Expander, ParaLink } from '@polkadot/react-components';
import { useApi, useCall, useCallMulti, useParaApi } from '@polkadot/react-hooks';
import { BlockToTime } from '@polkadot/react-query';
import { BN_ONE, formatNumber } from '@polkadot/util';
import { useTranslation } from '../translate';
import { sliceHex } from '../util';
interface Props {
@ -22,6 +23,7 @@ interface Props {
isScheduled?: boolean;
lastBacked?: [string, string, BN];
lastInclusion?: [string, string, BN];
validators?: AccountId[];
}
type QueryResult = [Option<HeadData>, Option<BlockNumber>, Vec<Codec>, Vec<Codec>, Vec<Codec>, Vec<Codec>, Option<BlockNumber>];
@ -63,7 +65,8 @@ const optionsMulti = {
})
};
function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, lastInclusion }: Props): React.ReactElement<Props> {
function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, lastInclusion, validators }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { api: paraApi } = useParaApi(id);
const paraBest = useCall<BlockNumber>(paraApi?.rpc.chain.subscribeNewHeads, undefined, transformHeader);
@ -89,6 +92,16 @@ function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, l
[bestNumber, lastRelayNumber, paraInfo]
);
const valRender = useCallback(
() => validators?.map((id) => (
<AddressMini
key={id.toString()}
value={id}
/>
)),
[validators]
);
return (
<tr className={className}>
<td className='number'><h1>{formatNumber(id)}</h1></td>
@ -99,6 +112,14 @@ function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, l
/>
)}</td>
<td className='badge together'><ParaLink id={id} /></td>
<td className='number media--1500'>
{validators && validators.length !== 0 && (
<Expander
renderChildren={valRender}
summary={t<string>('Validators ({{count}})', { replace: { count: formatNumber(validators.length) } })}
/>
)}
</td>
<td className='all start together hash'>{paraInfo.headHex}</td>
<td className='number'>{blockDelay && <BlockToTime blocks={blockDelay} />}</td>
<td className='number'>

View File

@ -2,14 +2,14 @@
// SPDX-License-Identifier: Apache-2.0
import type { SignedBlockExtended } from '@polkadot/api-derive/type';
import type { CandidateReceipt, Event, ParaId } from '@polkadot/types/interfaces';
import type { AccountId, CandidateReceipt, Event, ParaId, ParaValidatorIndex } from '@polkadot/types/interfaces';
import type { ScheduledProposals } from '../types';
import BN from 'bn.js';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { Table } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';
import { useApi, useCall, useCallMulti } from '@polkadot/react-hooks';
import { useTranslation } from '../translate';
import Parachain from './Parachain';
@ -26,6 +26,10 @@ interface LastEvents {
lastIncluded: EventMap;
}
const optionsMulti = {
defaultValue: [null, null] as [AccountId[] | null, ParaValidatorIndex[][] | null]
};
function includeEntry (map: EventMap, event: Event, blockHash: string, blockNumber: BN): void {
const { descriptor } = event.data[0] as CandidateReceipt;
@ -44,6 +48,10 @@ function ParachainList ({ ids, scheduled }: Props): React.ReactElement<Props> {
const bestNumber = useCall<BN>(api.derive.chain.bestNumber);
const lastBlock = useCall<SignedBlockExtended>(api.derive.chain.subscribeNewBlocks);
const [{ lastBacked, lastIncluded }, setLastEvents] = useState<LastEvents>({ lastBacked: {}, lastIncluded: {} });
const [validators, validatorGroups] = useCallMulti<[AccountId[] | null, ParaValidatorIndex[][] | null]>([
api.query.session.validators,
api.query.paraScheduler?.validatorGroups || api.query.scheduler?.validatorGroups
], optionsMulti);
const scheduledIds = useMemo(
() => (scheduled || []).reduce((all: Record<string, boolean>, { scheduledIds }: ScheduledProposals): Record<string, boolean> => {
@ -52,6 +60,17 @@ function ParachainList ({ ids, scheduled }: Props): React.ReactElement<Props> {
[scheduled]
);
const validatorMap = useMemo(
() => validators && validatorGroups && ids && ids.length === validatorGroups.length
? validatorGroups.map((ids) =>
ids
.map((id) => validators[id.toNumber()])
.filter((a) => a)
)
: [],
[ids, validators, validatorGroups]
);
useEffect((): void => {
lastBlock && setLastEvents((prev) => {
const backed: Record<string, [string, string, BN]> = {};
@ -88,6 +107,7 @@ function ParachainList ({ ids, scheduled }: Props): React.ReactElement<Props> {
const headerRef = useRef([
[t('parachains'), 'start', 3],
['', 'media--1500'],
[t('heads'), 'start'],
[t('included (parent)'), undefined, 2],
[t('backed')],
@ -101,7 +121,7 @@ function ParachainList ({ ids, scheduled }: Props): React.ReactElement<Props> {
empty={ids && t<string>('There are no registered parachains')}
header={headerRef.current}
>
{ids?.map((id): React.ReactNode => (
{ids?.map((id, index): React.ReactNode => (
<Parachain
bestNumber={bestNumber}
id={id}
@ -109,6 +129,7 @@ function ParachainList ({ ids, scheduled }: Props): React.ReactElement<Props> {
key={id.toString()}
lastBacked={lastBacked[id.toString()]}
lastInclusion={lastIncluded[id.toString()]}
validators={validatorMap[index]}
/>
))}
</Table>