From 66bba619a0525c1ae4bf8354a69465feda15334d Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 26 Jul 2024 14:42:11 +0200 Subject: [PATCH] Show RPC block number on chain page (#187) * Poll RPCs on chain page * Log errors temporarily * Revert * Improve formatting slightly * Populate RPC responses as they are received --- src/components/RpcTable.tsx | 104 +++++++++++++++++++++++----- src/pages/chain/{Chain.chainId}.tsx | 2 +- 2 files changed, 89 insertions(+), 17 deletions(-) diff --git a/src/components/RpcTable.tsx b/src/components/RpcTable.tsx index f2b3c09a2..0b1a9dd72 100644 --- a/src/components/RpcTable.tsx +++ b/src/components/RpcTable.tsx @@ -1,6 +1,7 @@ -import React, { useContext } from "react"; +import React, { useContext, useEffect, useState } from "react"; import { Button, + Skeleton, Table, TableContainer, Tbody, @@ -10,9 +11,62 @@ import { Tr, } from "@chakra-ui/react"; import { Web3Context } from "../context/Web3Context"; +import { JsonRpcProvider } from "ethers"; +import { ChainData } from "../types/chain"; -export const RpcTable = ({ rpcs, handleRpcClick }) => { +interface RpcResult { + rpcUrl: string; + blockNumber?: number; + latency?: number; + error?: unknown; +} + +async function checkRpc(chainId: number, rpcUrl: string): Promise { + try { + const now = Date.now(); + const provider = new JsonRpcProvider(rpcUrl, chainId, { + staticNetwork: true, + }); + const blockNumber = await provider.getBlockNumber(); + return { rpcUrl, blockNumber, latency: Date.now() - now }; + } catch (error) { + return { rpcUrl, error }; + } +} + +export const RpcTable = ({ + chainId, + rpcs, + handleRpcClick, +}: Pick & { + rpcs: ChainData["rpc"]; + handleRpcClick: (rpc: string) => void; +}) => { const { isConnected, handleConnect } = useContext(Web3Context); + const [rpcResults, setRpcResults] = useState(null); + + useEffect(() => { + rpcs.forEach((rpc) => + checkRpc(chainId, rpc).then((result) => { + setRpcResults((state) => [...(state ?? []), result]); + }) + ); + }, []); + + const mergedRpcs = rpcs + .map((rpcUrl) => { + const rpcResult = rpcResults?.find((result) => result.rpcUrl === rpcUrl); + return rpcResult ?? { rpcUrl }; + }) + .sort((a, b) => { + if (!a.latency) { + return 1; + } + if (!b.latency) { + return -1; + } + return a.latency < b.latency ? -1 : 1; + }); return ( @@ -20,24 +74,42 @@ export const RpcTable = ({ rpcs, handleRpcClick }) => { RPC URL + Block Number + Latency - {rpcs.map((rpcUrl) => ( - - {rpcUrl} - - {!isConnected ? ( - - ) : ( - - )} - - - ))} + {mergedRpcs.map(({ rpcUrl, blockNumber, latency, error }) => { + return ( + + {rpcUrl} + + {blockNumber || error ? ( + blockNumber ?? "Unavailable" + ) : ( + + )} + + + {latency || error ? ( + <>{latency ?? "?"} ms + ) : ( + + )} + + + {!isConnected ? ( + + ) : ( + + )} + + + ); + })} diff --git a/src/pages/chain/{Chain.chainId}.tsx b/src/pages/chain/{Chain.chainId}.tsx index bff377bdd..1056dd929 100644 --- a/src/pages/chain/{Chain.chainId}.tsx +++ b/src/pages/chain/{Chain.chainId}.tsx @@ -117,7 +117,7 @@ const ChainPage = ({ data }: { data: { chain: ChainData } }) => { )} - +