Show parachains last backed (#4446)
This commit is contained in:
parent
2d87138a6b
commit
54681c57b2
@ -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>];
|
||||
@ -35,7 +36,7 @@ interface QueryState {
|
||||
watermark: BlockNumber | null;
|
||||
}
|
||||
|
||||
const transformLast = {
|
||||
const transformHeader = {
|
||||
transform: (header: Header) => header.number.unwrap()
|
||||
};
|
||||
|
||||
@ -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],
|
||||
@ -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'>
|
||||
|
||||
@ -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';
|
||||
@ -19,48 +19,67 @@ 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]);
|
||||
@ -68,7 +87,8 @@ function ParachainList ({ ids, scheduled }: Props): React.ReactElement<Props> {
|
||||
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'],
|
||||
@ -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()]}
|
||||
/>
|
||||
))}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user