From 38e3206efed49aafde2aedc00ee625aaf0425958 Mon Sep 17 00:00:00 2001 From: Jaco Date: Fri, 15 Jul 2022 16:43:17 +0200 Subject: [PATCH] Don't fail full block decoding on event-only errors (#7878) --- .../page-explorer/src/BlockInfo/ByHash.tsx | 38 +++++++++------ .../page-explorer/src/BlockInfo/Extrinsic.tsx | 14 +++--- .../src/BlockInfo/Extrinsics.tsx | 2 +- .../page-explorer/src/BlockInfo/Summary.tsx | 4 +- packages/page-explorer/src/Events.tsx | 47 ++++++++++++------- 5 files changed, 64 insertions(+), 41 deletions(-) diff --git a/packages/page-explorer/src/BlockInfo/ByHash.tsx b/packages/page-explorer/src/BlockInfo/ByHash.tsx index e07383733b..ba02040ccf 100644 --- a/packages/page-explorer/src/BlockInfo/ByHash.tsx +++ b/packages/page-explorer/src/BlockInfo/ByHash.tsx @@ -26,7 +26,7 @@ interface Props { } interface State { - events?: KeyedEvent[]; + events?: KeyedEvent[] | null; getBlock?: SignedBlock; getHeader?: HeaderExtended; runtimeVersion?: RuntimeVersionPartial; @@ -34,9 +34,9 @@ interface State { const EMPTY_HEADER = [['...', 'start', 6]]; -function transformResult ([[runtimeVersion, events], getBlock, getHeader]: [[RuntimeVersionPartial, EventRecord[]], SignedBlock, HeaderExtended?]): State { +function transformResult ([[runtimeVersion, events], getBlock, getHeader]: [[RuntimeVersionPartial, EventRecord[] | null], SignedBlock, HeaderExtended?]): State { return { - events: events.map((record, index) => ({ + events: events && events.map((record, index) => ({ indexes: [index], key: `${Date.now()}-${index}-${record.hash.toHex()}`, record @@ -52,7 +52,8 @@ function BlockByHash ({ className = '', error, value }: Props): React.ReactEleme const { api } = useApi(); const mountedRef = useIsMountedRef(); const [{ events, getBlock, getHeader, runtimeVersion }, setState] = useState({}); - const [myError, setError] = useState(error); + const [blkError, setBlkError] = useState(error); + const [evtError, setEvtError] = useState(); const isVersionCurrent = useMemo( () => !!runtimeVersion && api.runtimeVersion.specName.eq(runtimeVersion.specName) && api.runtimeVersion.specVersion.eq(runtimeVersion.specVersion), @@ -62,12 +63,20 @@ function BlockByHash ({ className = '', error, value }: Props): React.ReactEleme useEffect((): void => { value && Promise .all([ - api.at(value).then((apiAt) => - Promise.all([ - Promise.resolve(apiAt.runtimeVersion), - apiAt.query.system.events() - ]) - ), + api + .at(value) + .then((apiAt) => + Promise.all([ + Promise.resolve(apiAt.runtimeVersion), + apiAt.query.system + .events() + .catch((error: Error) => { + mountedRef.current && setEvtError(error); + + return null; + }) + ]) + ), api.rpc.chain.getBlock(value), api.derive.chain.getHeader(value) ]) @@ -75,7 +84,7 @@ function BlockByHash ({ className = '', error, value }: Props): React.ReactEleme mountedRef.current && setState(transformResult(result)); }) .catch((error: Error): void => { - mountedRef.current && setError(error); + mountedRef.current && setBlkError(error); }); }, [api, mountedRef, value]); @@ -108,8 +117,8 @@ function BlockByHash ({ className = '', error, value }: Props): React.ReactEleme header={header} isFixed > - {myError - ? {t('Unable to retrieve the specified block details. {{error}}', { replace: { error: myError.message } })} + {blkError + ? {t('Unable to retrieve the specified block details. {{error}}', { replace: { error: blkError.message } })} : getBlock && getHeader && !getBlock.isEmpty && !getHeader.isEmpty && ( @@ -146,8 +155,9 @@ function BlockByHash ({ className = '', error, value }: Props): React.ReactEleme !phase.isApplyExtrinsic)} + events={events && events.filter(({ record: { phase } }) => !phase.isApplyExtrinsic)} label={t('system events')} /> diff --git a/packages/page-explorer/src/BlockInfo/Extrinsic.tsx b/packages/page-explorer/src/BlockInfo/Extrinsic.tsx index b163ef84f1..dd8696d11b 100644 --- a/packages/page-explorer/src/BlockInfo/Extrinsic.tsx +++ b/packages/page-explorer/src/BlockInfo/Extrinsic.tsx @@ -17,7 +17,7 @@ import { useTranslation } from '../translate'; interface Props { blockNumber?: BlockNumber; className?: string; - events?: KeyedEvent[]; + events?: KeyedEvent[] | null; index: number; maxBlockWeight?: Weight; value: Extrinsic; @@ -36,11 +36,13 @@ function getEra ({ era }: Extrinsic, blockNumber?: BlockNumber): [number, number return null; } -function filterEvents (index: number, events: KeyedEvent[] = [], maxBlockWeight?: Weight): [DispatchInfo | undefined, number, KeyedEvent[]] { - const filtered = events.filter(({ record: { phase } }) => - phase.isApplyExtrinsic && - phase.asApplyExtrinsic.eq(index) - ); +function filterEvents (index: number, events?: KeyedEvent[] | null, maxBlockWeight?: Weight): [DispatchInfo | undefined, number, KeyedEvent[]] { + const filtered = events + ? events.filter(({ record: { phase } }) => + phase.isApplyExtrinsic && + phase.asApplyExtrinsic.eq(index) + ) + : []; const infoRecord = filtered.find(({ record: { event: { method, section } } }) => section === 'system' && ['ExtrinsicFailed', 'ExtrinsicSuccess'].includes(method) diff --git a/packages/page-explorer/src/BlockInfo/Extrinsics.tsx b/packages/page-explorer/src/BlockInfo/Extrinsics.tsx index 1f7a994350..8d8e79651d 100644 --- a/packages/page-explorer/src/BlockInfo/Extrinsics.tsx +++ b/packages/page-explorer/src/BlockInfo/Extrinsics.tsx @@ -15,7 +15,7 @@ import ExtrinsicDisplay from './Extrinsic'; interface Props { blockNumber?: BlockNumber; className?: string; - events?: KeyedEvent[]; + events?: KeyedEvent[] | null; label?: React.ReactNode; value?: Extrinsic[] | null; withLink: boolean; diff --git a/packages/page-explorer/src/BlockInfo/Summary.tsx b/packages/page-explorer/src/BlockInfo/Summary.tsx index bd258b5c97..789d26cfbf 100644 --- a/packages/page-explorer/src/BlockInfo/Summary.tsx +++ b/packages/page-explorer/src/BlockInfo/Summary.tsx @@ -14,12 +14,12 @@ import { BN, formatNumber } from '@polkadot/util'; import { useTranslation } from '../translate'; interface Props { - events?: KeyedEvent[]; + events?: KeyedEvent[] | null; maxBlockWeight?: Weight; signedBlock?: SignedBlock; } -function extractEventDetails (events?: KeyedEvent[]): [BN?, BN?, BN?] { +function extractEventDetails (events?: KeyedEvent[] | null): [BN?, BN?, BN?] { return events ? events.reduce(([deposits, transfers, weight], { record: { event: { data, method, section } } }) => [ section === 'balances' && method === 'Deposit' diff --git a/packages/page-explorer/src/Events.tsx b/packages/page-explorer/src/Events.tsx index 52de4ee64f..03456010e1 100644 --- a/packages/page-explorer/src/Events.tsx +++ b/packages/page-explorer/src/Events.tsx @@ -15,13 +15,14 @@ import { useTranslation } from './translate'; interface Props { className?: string; + error?: Error; emptyLabel?: React.ReactNode; - events?: KeyedEvent[]; + events?: KeyedEvent[] | null; eventClassName?: string; label?: React.ReactNode; } -function Events ({ className = '', emptyLabel, eventClassName, events, label }: Props): React.ReactElement { +function Events ({ className = '', emptyLabel, error, eventClassName, events, label }: Props): React.ReactElement { const { t } = useTranslation(); const header = useMemo(() => [ @@ -34,22 +35,32 @@ function Events ({ className = '', emptyLabel, eventClassName, events, label }: empty={emptyLabel || t('No events available')} header={header} > - {events && events.map(({ blockHash, blockNumber, indexes, key, record }): React.ReactNode => ( - - - - {blockNumber && ( -
- {indexes.length !== 1 && ({formatNumber(indexes.length)}x) } - {formatNumber(blockNumber)}-{indexes[0]} -
- )} - - - ))} + {error + ? ( + + {error.message} + + ) + : events && events.map(({ blockHash, blockNumber, indexes, key, record }): React.ReactNode => ( + + + + {blockNumber && ( +
+ {indexes.length !== 1 && ({formatNumber(indexes.length)}x) } + {formatNumber(blockNumber)}-{indexes[0]} +
+ )} + + + )) + } ); }