From 120fb7799e050592631a227175eceee56c0febda Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 19 Mar 2021 16:06:31 +0100 Subject: [PATCH] Parachain voters (#4872) * Parachain voters * | null --- .../src/Overview/Parachain.tsx | 51 ++++++++++++++++--- .../src/Overview/Parachains.tsx | 1 + 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/packages/page-parachains/src/Overview/Parachain.tsx b/packages/page-parachains/src/Overview/Parachain.tsx index deff8c9d0c..66b1367a10 100644 --- a/packages/page-parachains/src/Overview/Parachain.tsx +++ b/packages/page-parachains/src/Overview/Parachain.tsx @@ -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, Option, Option, Vec, Vec, Vec, Vec, Option]; +type QueryResult = [Option, Option, Option, Vec, Vec, Vec, Vec, Option, Option]; 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 { +function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, lastInclusion, nextAction, sessionValidators, validators }: Props): React.ReactElement { 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([]); const blockDelay = useMemo( () => bestNumber && ( @@ -108,6 +114,33 @@ function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, l [validators] ); + const bckRender = useCallback( + () => nonBacked.map((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 (

{formatNumber(id)}

@@ -125,6 +158,12 @@ function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, l summary={t('Validators ({{count}})', { replace: { count: formatNumber(validators.length) } })} /> )} + {nonBacked && ( + ('Non-voters ({{count}})', { replace: { count: formatNumber(nonBacked.length) } })} + /> + )} {paraInfo.headHex} diff --git a/packages/page-parachains/src/Overview/Parachains.tsx b/packages/page-parachains/src/Overview/Parachains.tsx index e334004a17..d003eebf43 100644 --- a/packages/page-parachains/src/Overview/Parachains.tsx +++ b/packages/page-parachains/src/Overview/Parachains.tsx @@ -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]} /> ))}