Parachain voters (#4872)

* Parachain voters

* | null
This commit is contained in:
Jaco Greeff 2021-03-19 16:06:31 +01:00 committed by GitHub
parent 6e85de4730
commit 120fb7799e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 6 deletions

View File

@ -2,12 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
import type { Option, Vec } from '@polkadot/types';
import type { AccountId, BlockNumber, HeadData, Header, ParaId, ParaLifecycle } from '@polkadot/types/interfaces';
import type { AccountId, BlockNumber, CandidatePendingAvailability, HeadData, Header, ParaId, ParaLifecycle } from '@polkadot/types/interfaces';
import type { Codec } from '@polkadot/types/types';
import type { QueuedAction } from './types';
import BN from 'bn.js';
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { AddressMini, Badge, Expander, ParaLink } from '@polkadot/react-components';
import { useApi, useCall, useCallMulti, useParaApi } from '@polkadot/react-hooks';
@ -26,14 +26,16 @@ interface Props {
lastBacked?: [string, string, BN];
lastInclusion?: [string, string, BN];
nextAction?: QueuedAction;
sessionValidators?: AccountId[] | null;
validators?: AccountId[];
}
type QueryResult = [Option<HeadData>, Option<BlockNumber>, Option<ParaLifecycle>, Vec<Codec>, Vec<Codec>, Vec<Codec>, Vec<Codec>, Option<BlockNumber>];
type QueryResult = [Option<HeadData>, Option<BlockNumber>, Option<ParaLifecycle>, Vec<Codec>, Vec<Codec>, Vec<Codec>, Vec<Codec>, Option<BlockNumber>, Option<CandidatePendingAvailability>];
interface QueryState {
headHex: string | null;
lifecycle: ParaLifecycle | null;
pendingAvail: CandidatePendingAvailability | null;
updateAt: BlockNumber | null;
qDmp: number;
qUmp: number;
@ -50,6 +52,7 @@ const optionsMulti = {
defaultValue: {
headHex: null,
lifecycle: null,
pendingAvail: null,
qDmp: 0,
qHrmpE: 0,
qHrmpI: 0,
@ -57,11 +60,12 @@ const optionsMulti = {
updateAt: null,
watermark: null
},
transform: ([headData, optUp, optLifecycle, dmp, ump, hrmpE, hrmpI, optWm]: QueryResult): QueryState => ({
transform: ([headData, optUp, optLifecycle, dmp, ump, hrmpE, hrmpI, optWm, optPending]: QueryResult): QueryState => ({
headHex: headData.isSome
? sliceHex(headData.unwrap())
: null,
lifecycle: optLifecycle.unwrapOr(null),
pendingAvail: optPending.unwrapOr(null),
qDmp: dmp.length,
qHrmpE: hrmpE.length,
qHrmpI: hrmpI.length,
@ -71,7 +75,7 @@ const optionsMulti = {
})
};
function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, lastInclusion, nextAction, validators }: Props): React.ReactElement<Props> {
function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, lastInclusion, nextAction, sessionValidators, validators }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { api: paraApi } = useParaApi(id);
@ -84,8 +88,10 @@ function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, l
[api.query.ump.relayDispatchQueues, id],
[api.query.hrmp.hrmpEgressChannelsIndex, id],
[api.query.hrmp.hrmpIngressChannelsIndex, id],
[api.query.hrmp.hrmpWatermarks, id]
[api.query.hrmp.hrmpWatermarks, id],
[api.query.inclusion.pendingAvailability, id]
], optionsMulti);
const [nonBacked, setNonBacked] = useState<AccountId[]>([]);
const blockDelay = useMemo(
() => bestNumber && (
@ -108,6 +114,33 @@ function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, l
[validators]
);
const bckRender = useCallback(
() => nonBacked.map((id) => (
<AddressMini
key={id.toString()}
value={id}
/>
)),
[nonBacked]
);
useEffect((): void => {
if (sessionValidators) {
if (paraInfo.pendingAvail) {
const list = paraInfo.pendingAvail.availabilityVotes.toHuman()
.slice(2)
.replace(/_/g, '')
.split('')
.map((c, index) => c === '0' ? sessionValidators[index] : null)
.filter((v, index): v is AccountId => !!v && index < sessionValidators.length);
list.length !== sessionValidators.length && setNonBacked(list);
} else {
setNonBacked([]);
}
}
}, [paraInfo, sessionValidators]);
return (
<tr className={className}>
<td className='number'><h1>{formatNumber(id)}</h1></td>
@ -125,6 +158,12 @@ function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, l
summary={t<string>('Validators ({{count}})', { replace: { count: formatNumber(validators.length) } })}
/>
)}
{nonBacked && (
<Expander
renderChildren={bckRender}
summary={t<string>('Non-voters ({{count}})', { replace: { count: formatNumber(nonBacked.length) } })}
/>
)}
</td>
<td className='start together hash'>{paraInfo.headHex}</td>
<td className='start media--1100'>

View File

@ -136,6 +136,7 @@ function Parachains ({ actionsQueue, ids, scheduled }: Props): React.ReactElemen
nextAction={actionsQueue.find(({ paraIds }) =>
paraIds.some((p) => p.eq(id))
)}
sessionValidators={validators}
validators={validatorMap[index]}
/>
))}