Skip to content

Commit

Permalink
Show parachains last backed (polkadot-js#4446)
Browse files Browse the repository at this point in the history
  • Loading branch information
jacogr authored Jan 18, 2021
1 parent 2d87138 commit 54681c5
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 31 deletions.
14 changes: 10 additions & 4 deletions packages/page-parachains/src/Overview/Parachain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 20,8 @@ interface Props {
className?: string;
id: ParaId;
isScheduled?: boolean;
lastInclusion?: [string, string];
lastBacked?: [string, string, BN];
lastInclusion?: [string, string, BN];
}

type QueryResult = [Option<HeadData>, Option<BlockNumber>, Vec<Codec>, Vec<Codec>, Vec<Codec>, Vec<Codec>, Option<BlockNumber>];
Expand All @@ -35,7 36,7 @@ interface QueryState {
watermark: BlockNumber | null;
}

const transformLast = {
const transformHeader = {
transform: (header: Header) => header.number.unwrap()
};

Expand All @@ -62,12 63,12 @@ const optionsMulti = {
})
};

function Parachain ({ bestNumber, className = '', id, isScheduled, lastInclusion }: Props): React.ReactElement<Props> {
function Parachain ({ bestNumber, className = '', id, isScheduled, lastBacked, lastInclusion }: Props): React.ReactElement<Props> {
const { api } = useApi();
const { api: paraApi, endpoints } = useParaApi(id);
const paraBest = useCall<BlockNumber>(paraApi?.derive.chain.bestNumber);
const paraIssu = useCall<Balance>(paraApi?.query.balances?.totalIssuance);
const lastRelayNumber = useCall<BN>(lastInclusion && api.rpc.chain.getHeader, [lastInclusion && lastInclusion[1]], transformLast);
const lastRelayNumber = useCall<BN>(lastInclusion && api.rpc.chain.getHeader, [lastInclusion && lastInclusion[1]], transformHeader);
const paraInfo = useCallMulti<QueryState>([
[api.query.paras.heads, id],
[api.query.paras.futureCodeUpgrades, id],
Expand Down Expand Up @@ -112,6 113,11 @@ function Parachain ({ bestNumber, className = '', id, isScheduled, lastInclusion
: paraInfo.watermark && formatNumber(paraInfo.watermark)
}
</td>
<td className='number'>
{lastBacked &&
<a href={`#/explorer/query/${lastBacked[0]}`}>{formatNumber(lastBacked[2])}</a>
}
</td>
<td className='number media--900'>{paraBest && <>{formatNumber(paraBest)}</>}</td>
<td className='number media--1100'>{paraIssu && <FormatBalance valueFormatted={paraIssu.toHuman()} />}</td>
<td className='number media--1300'>
Expand Down
75 changes: 48 additions & 27 deletions packages/page-parachains/src/Overview/ParachainList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 2,7 @@
// SPDX-License-Identifier: Apache-2.0

import type { SignedBlockExtended } from '@polkadot/api-derive/type';
import type { CandidateReceipt, ParaId } from '@polkadot/types/interfaces';
import type { CandidateReceipt, Event, ParaId } from '@polkadot/types/interfaces';
import type { ScheduledProposals } from '../types';

import BN from 'bn.js';
Expand All @@ -19,56 19,76 @@ interface Props {
scheduled?: ScheduledProposals[];
}

type EventMap = Record<string, [string, string, BN]>;

interface LastEvents {
lastBacked: EventMap;
lastIncluded: EventMap;
}

function includeEntry (map: EventMap, event: Event, blockHash: string, blockNumber: BN): void {
const { descriptor } = event.data[0] as CandidateReceipt;

map[descriptor.paraId.toString()] = [
blockHash,
descriptor.relayParent.toHex(),
blockNumber
];
}

function ParachainList ({ ids, scheduled }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const bestNumber = useCall<BN>(api.derive.chain.bestNumber);
const lastBlock = useCall<SignedBlockExtended>(api.derive.chain.subscribeNewBlocks);
const [lastIncluded, setLastIncluded] = useState<Record<string, [string, string]>>({});
const [{ lastBacked, lastIncluded }, setLastEvents] = useState<LastEvents>({ lastBacked: {}, lastIncluded: {} });

const scheduledIds = useMemo(
() => scheduled
? scheduled.reduce((all: Record<string, boolean>, { scheduledIds }: ScheduledProposals): Record<string, boolean> => {
return scheduledIds.reduce((all: Record<string, boolean>, id) => ({ ...all, [id.toString()]: true }), all);
}, {})
: {},
() => (scheduled || []).reduce((all: Record<string, boolean>, { scheduledIds }: ScheduledProposals): Record<string, boolean> => {
return scheduledIds.reduce((all: Record<string, boolean>, id) => ({ ...all, [id.toString()]: true }), all);
}, {}),
[scheduled]
);

useEffect((): void => {
lastBlock && setLastIncluded((prev) => {
const updated: Record<string, [string, string]> = {};
lastBlock && setLastEvents((prev) => {
const backed: Record<string, [string, string, BN]> = {};
const included: Record<string, [string, string, BN]> = {};
const blockNumber = lastBlock.block.header.number.unwrap();
const blockHash = lastBlock.block.header.hash.toHex();
let wasUpdated = false;
let wasIncluded = false;
let wasBacked = false;

lastBlock.events.forEach(({ event, phase }) => {
if (phase.isApplyExtrinsic && api.events.inclusion.CandidateBacked.is(event)) {
const { descriptor } = event.data[0] as CandidateReceipt;

updated[descriptor.paraId.toString()] = [
blockHash,
descriptor.relayParent.toHex()
];
wasUpdated = true;
if (phase.isApplyExtrinsic) {
if (api.events.inclusion.CandidateBacked.is(event)) {
includeEntry(backed, event, blockHash, blockNumber);
wasBacked = true;
} else if (api.events.inclusion.CandidateIncluded.is(event)) {
includeEntry(included, event, blockHash, blockNumber);
wasIncluded = true;
}
}
});

return wasUpdated
? Object.entries(prev).reduce((updated: Record<string, [string, string]>, [id, hashes]): Record<string, [string, string]> => {
if (!updated[id]) {
updated[id] = hashes;
}

return updated;
}, updated)
return wasBacked || wasIncluded
? {
lastBacked: wasBacked
? { ...prev.lastBacked, ...backed }
: prev.lastBacked,
lastIncluded: wasIncluded
? { ...prev.lastIncluded, ...included }
: prev.lastIncluded
}
: prev;
});
}, [api, lastBlock]);

const headerRef = useRef([
[t('parachains'), 'start', 3],
[t('heads'), 'start'],
[t('relay parent'), undefined, 2],
[t('included (parent)'), undefined, 2],
[t('backed')],
[t('chain best'), 'media--900'],
[t('issuance'), 'media--1100'],
[t('upgrade'), 'media--1300'],
Expand All @@ -86,6 106,7 @@ function ParachainList ({ ids, scheduled }: Props): React.ReactElement<Props> {
id={id}
isScheduled={scheduledIds[id.toString()]}
key={id.toString()}
lastBacked={lastBacked[id.toString()]}
lastInclusion={lastIncluded[id.toString()]}
/>
))}
Expand Down

0 comments on commit 54681c5

Please sign in to comment.