Skip to content

Commit

Permalink
Merge pull request #735 from blockscout/blocks/consensus-lost
Browse files Browse the repository at this point in the history
display error when block has lost consensus
  • Loading branch information
tom2drum authored Apr 10, 2023
2 parents be08fd5 + 6f85391 commit c876efe
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 17 deletions.
8 changes: 8 additions & 0 deletions lib/errors/getErrorCause.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default function getErrorCause(error: Error | undefined): Record<string, unknown> | undefined {
return (
error && 'cause' in error &&
typeof error.cause === 'object' && error.cause !== null &&
error.cause as Record<string, unknown>
) ||
undefined;
}
11 changes: 4 additions & 7 deletions lib/errors/getErrorStatusCode.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import getErrorCause from './getErrorCause';

export default function getErrorStatusCode(error: Error | undefined): number | undefined {
return (
error && 'cause' in error &&
typeof error.cause === 'object' && error.cause !== null &&
'status' in error.cause && typeof error.cause.status === 'number' &&
error.cause.status
) ||
undefined;
const cause = getErrorCause(error);
return cause && 'status' in cause && typeof cause.status === 'number' ? cause.status : undefined;
}
8 changes: 8 additions & 0 deletions lib/errors/getResourceErrorPayload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { ResourceError } from 'lib/api/resources';

import getErrorCause from './getErrorCause';

export default function getResourceErrorPayload<Payload = Record<string, unknown>>(error: Error | undefined): ResourceError<Payload>['payload'] | undefined {
const cause = getErrorCause(error);
return cause && 'payload' in cause ? cause.payload as ResourceError<Payload>['payload'] : undefined;
}
5 changes: 4 additions & 1 deletion pages/block/[height].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React from 'react';

import getSeo from 'lib/next/block/getSeo';
import Block from 'ui/pages/Block';
import Page from 'ui/shared/Page/Page';

const BlockPage: NextPage<RoutedQuery<'/block/[height]'>> = ({ height }: RoutedQuery<'/block/[height]'>) => {
const { title, description } = getSeo({ height });
Expand All @@ -14,7 +15,9 @@ const BlockPage: NextPage<RoutedQuery<'/block/[height]'>> = ({ height }: RoutedQ
<title>{ title }</title>
<meta name="description" content={ description }/>
</Head>
<Block/>
<Page>
<Block/>
</Page>
</>
);
};
Expand Down
11 changes: 7 additions & 4 deletions ui/pages/Block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import getQueryParamString from 'lib/router/getQueryParamString';
import BlockDetails from 'ui/block/BlockDetails';
import TextAd from 'ui/shared/ad/TextAd';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/Pagination';
import RoutedTabs from 'ui/shared/RoutedTabs/RoutedTabs';
Expand Down Expand Up @@ -39,14 +38,18 @@ const BlockPageContent = () => {
resourceName: 'block_txs',
pathParams: { height },
options: {
enabled: Boolean(height && tab === 'txs'),
enabled: Boolean(blockQuery.data?.height && tab === 'txs'),
},
});

if (!height) {
throw new Error('Block not found', { cause: { status: 404 } });
}

if (blockQuery.isError) {
throw new Error(undefined, { cause: blockQuery.error });
}

const tabs: Array<RoutedTab> = React.useMemo(() => ([
{ id: 'index', title: 'Details', component: <BlockDetails query={ blockQuery }/> },
{ id: 'txs', title: 'Transactions', component: <TxsContent query={ blockTxsQuery } showBlockInfo={ false } showSocketInfo={ false }/> },
Expand All @@ -57,7 +60,7 @@ const BlockPageContent = () => {
const hasGoBackLink = appProps.referrer && appProps.referrer.includes('/blocks');

return (
<Page>
<>
{ blockQuery.isLoading ? <Skeleton h={{ base: 12, lg: 6 }} mb={ 6 } w="100%" maxW="680px"/> : <TextAd mb={ 6 }/> }
{ blockQuery.isLoading ? (
<Skeleton h={ 10 } w="300px" mb={ 6 }/>
Expand All @@ -74,7 +77,7 @@ const BlockPageContent = () => {
rightSlot={ hasPagination ? <Pagination { ...blockTxsQuery.pagination }/> : null }
stickyEnabled={ hasPagination }
/>
</Page>
</>
);
};

Expand Down
30 changes: 30 additions & 0 deletions ui/shared/AppError/AppErrorBlockConsensus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Box, Button, Heading, Icon, chakra } from '@chakra-ui/react';
import { route } from 'nextjs-routes';
import React from 'react';

import icon404 from 'icons/error-pages/404.svg';

interface Props {
hash?: string;
className?: string;
}

const AppErrorBlockConsensus = ({ hash, className }: Props) => {
return (
<Box className={ className }>
<Icon as={ icon404 } width="200px" height="auto"/>
<Heading mt={ 8 } size="2xl" fontFamily="body">Block has lost consensus</Heading>
<Button
mt={ 8 }
size="lg"
variant="outline"
as="a"
href={ hash ? route({ pathname: '/block/[height]', query: { height: hash } }) : route({ pathname: '/' }) }
>
{ hash ? 'View reorg' : 'Back to home' }
</Button>
</Box>
);
};

export default chakra(AppErrorBlockConsensus);
24 changes: 19 additions & 5 deletions ui/shared/Page/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { Flex } from '@chakra-ui/react';
import React from 'react';

import getErrorStatusCode from 'lib/errors/getErrorStatusCode';
import getResourceErrorPayload from 'lib/errors/getResourceErrorPayload';
import useAdblockDetect from 'lib/hooks/useAdblockDetect';
import useGetCsrfToken from 'lib/hooks/useGetCsrfToken';
import AppError from 'ui/shared/AppError/AppError';
import AppErrorBlockConsensus from 'ui/shared/AppError/AppErrorBlockConsensus';
import ErrorBoundary from 'ui/shared/ErrorBoundary';
import ErrorInvalidTxHash from 'ui/shared/ErrorInvalidTxHash';
import PageContent from 'ui/shared/Page/PageContent';
Expand All @@ -31,15 +33,27 @@ const Page = ({

const renderErrorScreen = React.useCallback((error?: Error) => {
const statusCode = getErrorStatusCode(error) || 500;
const resourceErrorPayload = getResourceErrorPayload(error);
const messageInPayload = resourceErrorPayload && 'message' in resourceErrorPayload && typeof resourceErrorPayload.message === 'string' ?
resourceErrorPayload.message :
undefined;

const isInvalidTxHash = error?.message.includes('Invalid tx hash');
const isBlockConsensus = messageInPayload?.includes('Block lost consensus');

if (isInvalidTxHash) {
return <PageContent isHomePage={ isHomePage }><ErrorInvalidTxHash/></PageContent>;
}

if (wrapChildren) {
const content = isInvalidTxHash ? <ErrorInvalidTxHash/> : <AppError statusCode={ statusCode } mt="50px"/>;
return <PageContent isHomePage={ isHomePage }>{ content }</PageContent>;
if (isBlockConsensus) {
const hash = resourceErrorPayload && 'hash' in resourceErrorPayload && typeof resourceErrorPayload.hash === 'string' ?
resourceErrorPayload.hash :
undefined;
return <PageContent isHomePage={ isHomePage }><AppErrorBlockConsensus hash={ hash } mt="50px"/></PageContent>;
}

return isInvalidTxHash ? <ErrorInvalidTxHash/> : <AppError statusCode={ statusCode }/>;
}, [ isHomePage, wrapChildren ]);
return <PageContent isHomePage={ isHomePage }><AppError statusCode={ statusCode } mt="50px"/></PageContent>;
}, [ isHomePage ]);

const renderedChildren = wrapChildren ? (
<PageContent isHomePage={ isHomePage }>{ children }</PageContent>
Expand Down

0 comments on commit c876efe

Please sign in to comment.