mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
Block countdown. Infinite loop if 404 block is in the past. (#3130)
* Block countdown. Infinite loop if 404 block is in the past. Resolves #3124 * fix test
This commit is contained in:
@@ -4,12 +4,12 @@ import type { PublicRpcSchema } from 'viem';
|
||||
|
||||
import { getEnvValue } from 'configs/app/utils';
|
||||
|
||||
type Params = PublicRpcSchema[number];
|
||||
type Params = Array<PublicRpcSchema[number]>;
|
||||
|
||||
export type MockRpcResponseFixture = (params: Params) => Promise<void>;
|
||||
|
||||
const fixture: TestFixture<MockRpcResponseFixture, { page: Page }> = async({ page }, use) => {
|
||||
await use(async(rpcMock) => {
|
||||
await use(async(rpcMocks) => {
|
||||
const rpcUrl = getEnvValue('NEXT_PUBLIC_NETWORK_RPC_URL');
|
||||
|
||||
if (!rpcUrl) {
|
||||
@@ -27,14 +27,23 @@ const fixture: TestFixture<MockRpcResponseFixture, { page: Page }> = async({ pag
|
||||
const json = route.request().postDataJSON();
|
||||
const id = json?.id;
|
||||
|
||||
const payload = {
|
||||
id,
|
||||
jsonrpc: '2.0',
|
||||
method: rpcMock.Method,
|
||||
...(rpcMock.Parameters ? { params: rpcMock.Parameters } : {}),
|
||||
};
|
||||
if (id === undefined) {
|
||||
route.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEqual(json, payload) && id !== undefined) {
|
||||
const rpcMock = rpcMocks.find((mock) => {
|
||||
const payload = {
|
||||
id,
|
||||
jsonrpc: '2.0',
|
||||
method: mock.Method,
|
||||
...(mock.Parameters ? { params: mock.Parameters } : {}),
|
||||
};
|
||||
|
||||
return isEqual(json, payload);
|
||||
});
|
||||
|
||||
if (rpcMock) {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
json: {
|
||||
|
||||
@@ -19,6 +19,7 @@ type RpcResponseType = GetBlockReturnType<Chain, false, 'latest'> | null;
|
||||
|
||||
export type BlockQuery = UseQueryResult<Block, ResourceError<{ status: number }>> & {
|
||||
isDegradedData: boolean;
|
||||
isFutureBlock: boolean;
|
||||
};
|
||||
|
||||
interface Params {
|
||||
@@ -47,6 +48,17 @@ export default function useBlockQuery({ heightOrHash }: Params): BlockQuery {
|
||||
},
|
||||
});
|
||||
|
||||
const latestBlockQuery = useQuery({
|
||||
queryKey: [ 'RPC', 'block', 'latest' ],
|
||||
queryFn: async() => {
|
||||
if (!publicClient) {
|
||||
return null;
|
||||
}
|
||||
return publicClient.getBlock({ blockTag: 'latest' });
|
||||
},
|
||||
enabled: publicClient !== undefined && (apiQuery.isError || apiQuery.errorUpdateCount > 0),
|
||||
});
|
||||
|
||||
const rpcQuery = useQuery<RpcResponseType, unknown, Block | null>({
|
||||
queryKey: [ 'RPC', 'block', { heightOrHash } ],
|
||||
queryFn: async() => {
|
||||
@@ -91,7 +103,7 @@ export default function useBlockQuery({ heightOrHash }: Params): BlockQuery {
|
||||
};
|
||||
},
|
||||
placeholderData: GET_BLOCK,
|
||||
enabled: publicClient !== undefined && (apiQuery.isError || apiQuery.errorUpdateCount > 0),
|
||||
enabled: !latestBlockQuery.isPending,
|
||||
retry: false,
|
||||
refetchOnMount: false,
|
||||
});
|
||||
@@ -120,5 +132,9 @@ export default function useBlockQuery({ heightOrHash }: Params): BlockQuery {
|
||||
return {
|
||||
...query,
|
||||
isDegradedData: isRpcQuery,
|
||||
isFutureBlock: Boolean(
|
||||
!heightOrHash.startsWith('0x') &&
|
||||
latestBlockQuery.data && Number(latestBlockQuery.data.number) < Number(heightOrHash),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,11 +44,11 @@ test('degradation view', async({ render, page, mockRpcResponse, mockApiResponse
|
||||
await mockApiResponse('general:address_counters', addressCountersMock.forValidator, { pathParams: { hash: addressMock.hash } });
|
||||
await mockApiResponse('general:address_tabs_counters', null as never, { pathParams: { hash: addressMock.hash }, status: 500 });
|
||||
await mockApiResponse('general:address_txs', null as never, { pathParams: { hash: addressMock.hash }, status: 500 });
|
||||
await mockRpcResponse({
|
||||
await mockRpcResponse([ {
|
||||
Method: 'eth_getBalance',
|
||||
Parameters: [ addressMock.hash, 'latest' ],
|
||||
ReturnType: numberToHex(1234567890123456),
|
||||
});
|
||||
} ]);
|
||||
|
||||
const component = await render(<Address/>, { hooksConfig });
|
||||
await page.waitForResponse(config.chain.rpcUrls[0]);
|
||||
|
||||
+45
-15
@@ -21,11 +21,21 @@ test.beforeEach(async({ mockTextAd }) => {
|
||||
|
||||
test('degradation view, details tab', async({ render, mockApiResponse, mockRpcResponse, page }) => {
|
||||
await mockApiResponse('general:block', null as never, { pathParams: { height_or_hash: height }, status: 500 });
|
||||
await mockRpcResponse({
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ numberToHex(Number(height)), false ],
|
||||
ReturnType: blockMock.rpcBlockBase,
|
||||
});
|
||||
await mockRpcResponse([
|
||||
{
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ 'latest', false ],
|
||||
ReturnType: {
|
||||
...blockMock.rpcBlockBase,
|
||||
number: String(Number(height) + 1_000) as `0x${ string }`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ numberToHex(Number(height)), false ],
|
||||
ReturnType: blockMock.rpcBlockBase,
|
||||
},
|
||||
]);
|
||||
|
||||
const component = await render(<Block/>, { hooksConfig });
|
||||
await page.waitForResponse(config.chain.rpcUrls[0]);
|
||||
@@ -42,11 +52,21 @@ test('degradation view, txs tab', async({ render, mockApiResponse, mockRpcRespon
|
||||
|
||||
await mockApiResponse('general:block', blockMock.base, { pathParams: { height_or_hash: height } });
|
||||
await mockApiResponse('general:block_txs', null as never, { pathParams: { height_or_hash: height }, status: 500 });
|
||||
await mockRpcResponse({
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ numberToHex(Number(height)), true ],
|
||||
ReturnType: blockMock.rpcBlockWithTxsInfo,
|
||||
});
|
||||
await mockRpcResponse([
|
||||
{
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ 'latest', false ],
|
||||
ReturnType: {
|
||||
...blockMock.rpcBlockWithTxsInfo,
|
||||
number: String(Number(height) + 1_000) as `0x${ string }`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ numberToHex(Number(height)), true ],
|
||||
ReturnType: blockMock.rpcBlockWithTxsInfo,
|
||||
},
|
||||
]);
|
||||
|
||||
const component = await render(<Block/>, { hooksConfig });
|
||||
await page.waitForResponse(config.chain.rpcUrls[0]);
|
||||
@@ -64,11 +84,21 @@ test('degradation view, withdrawals tab', async({ render, mockApiResponse, mockR
|
||||
await mockEnvs(ENVS_MAP.beaconChain);
|
||||
await mockApiResponse('general:block', blockMock.withWithdrawals, { pathParams: { height_or_hash: height } });
|
||||
await mockApiResponse('general:block_withdrawals', null as never, { pathParams: { height_or_hash: height }, status: 500 });
|
||||
await mockRpcResponse({
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ numberToHex(Number(height)), false ],
|
||||
ReturnType: blockMock.rpcBlockBase,
|
||||
});
|
||||
await mockRpcResponse([
|
||||
{
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ 'latest', false ],
|
||||
ReturnType: {
|
||||
...blockMock.rpcBlockBase,
|
||||
number: String(Number(height) + 1_000) as `0x${ string }`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Method: 'eth_getBlockByNumber',
|
||||
Parameters: [ numberToHex(Number(height)), false ],
|
||||
ReturnType: blockMock.rpcBlockBase,
|
||||
},
|
||||
]);
|
||||
|
||||
const component = await render(<Block/>, { hooksConfig });
|
||||
await page.waitForResponse(config.chain.rpcUrls[0]);
|
||||
|
||||
+1
-1
@@ -148,7 +148,7 @@ const BlockPageContent = () => {
|
||||
throwOnAbsentParamError(heightOrHash);
|
||||
|
||||
if (blockQuery.isError) {
|
||||
if (!blockQuery.isDegradedData && blockQuery.error.status === 404 && !heightOrHash.startsWith('0x')) {
|
||||
if (!blockQuery.isDegradedData && blockQuery.error.status === 404 && !heightOrHash.startsWith('0x') && blockQuery.isFutureBlock) {
|
||||
const url = routeParams({ pathname: '/block/countdown/[height]', query: { height: heightOrHash } }, multichainContext);
|
||||
router.push(url, undefined, { shallow: true });
|
||||
return null;
|
||||
|
||||
@@ -22,10 +22,10 @@ const testFn = async({ render, mockAssetResponse, mockEnvs, mockRpcResponse, moc
|
||||
]);
|
||||
await mockApiResponse('admin:marketplace_dapp', appsMock[0], { pathParams: { chainId: config.chain.id, dappId: appsMock[0].id } });
|
||||
await mockAssetResponse(appsMock[0].url, './mocks/apps/app.html');
|
||||
await mockRpcResponse({
|
||||
await mockRpcResponse([ {
|
||||
Method: 'eth_chainId',
|
||||
ReturnType: numberToHex(Number(config.chain.id)),
|
||||
});
|
||||
} ]);
|
||||
|
||||
const component = await render(
|
||||
<Flex flexDirection="column" mx={{ base: 4, lg: 6 }} h="100vh">
|
||||
|
||||
Reference in New Issue
Block a user