Add beacon chain finalized state info
This commit is contained in:
parent
81b9213df1
commit
08d8cded31
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"erigonURL": "http://localhost:8545",
|
||||
"beaconAPI": null,
|
||||
"assetsURLPrefix": "http://localhost:3001"
|
||||
}
|
17
src/Home.tsx
17
src/Home.tsx
|
@ -10,6 +10,7 @@ import { RuntimeContext } from "./useRuntime";
|
|||
import { useLatestBlockHeader } from "./useLatestBlock";
|
||||
import { blockURL } from "./url";
|
||||
import { useGenericSearch } from "./search/search";
|
||||
import { useFinalizedSlot, useSlotTime } from "./useBeacon";
|
||||
|
||||
const CameraScanner = React.lazy(() => import("./search/CameraScanner"));
|
||||
|
||||
|
@ -18,6 +19,8 @@ const Home: React.FC = () => {
|
|||
const [searchRef, handleChange, handleSubmit] = useGenericSearch();
|
||||
|
||||
const latestBlock = useLatestBlockHeader(provider);
|
||||
const beaconData = useFinalizedSlot();
|
||||
const slotTime = useSlotTime(beaconData?.data.header.message.slot);
|
||||
const [isScanning, setScanning] = useState<boolean>(false);
|
||||
|
||||
document.title = "Home | Otterscan";
|
||||
|
@ -87,6 +90,20 @@ const Home: React.FC = () => {
|
|||
<Timestamp value={latestBlock.timestamp} />
|
||||
</NavLink>
|
||||
)}
|
||||
{beaconData && (
|
||||
<div className="flex flex-col items-center space-y-1 mt-5 text-sm text-gray-500">
|
||||
<div>
|
||||
Finalized slot: {commify(beaconData.data.header.message.slot)}
|
||||
</div>
|
||||
{slotTime && <Timestamp value={slotTime} />}
|
||||
<div>
|
||||
State root:{" "}
|
||||
<span className="font-hash">
|
||||
{beaconData.data.header.message.state_root}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import { useContext } from "react";
|
||||
import useSWR from "swr";
|
||||
import useSWRImmutable from "swr/immutable";
|
||||
import { RuntimeContext } from "./useRuntime";
|
||||
|
||||
// 12s
|
||||
const SLOT_TIME = 12;
|
||||
|
||||
// TODO: remove duplication with other json fetchers
|
||||
const jsonFetcher = async (url: string) => {
|
||||
try {
|
||||
const res = await fetch(url);
|
||||
if (res.ok) {
|
||||
return res.json();
|
||||
}
|
||||
return null;
|
||||
} catch (err) {
|
||||
console.warn(`error while getting beacon data: url=${url} err=${err}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const useFinalizedSlot = () => {
|
||||
const { config } = useContext(RuntimeContext);
|
||||
|
||||
// Each slot is 12s, so program SWR to revalidate at this interval
|
||||
const { data, error } = useSWR(
|
||||
config?.beaconAPI
|
||||
? `${config?.beaconAPI}/eth/v1/beacon/headers/finalized`
|
||||
: null,
|
||||
jsonFetcher,
|
||||
{
|
||||
revalidateOnFocus: false,
|
||||
refreshInterval: SLOT_TIME * 1000,
|
||||
}
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return undefined;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
export const useBeaconGenesis = () => {
|
||||
const { config } = useContext(RuntimeContext);
|
||||
|
||||
const { data, error } = useSWRImmutable(
|
||||
config?.beaconAPI ? `${config?.beaconAPI}/eth/v1/beacon/genesis` : null,
|
||||
jsonFetcher
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return undefined;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
export const useSlotTime = (slot: number | undefined): number | undefined => {
|
||||
const genesis = useBeaconGenesis();
|
||||
if (slot === undefined || genesis === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const rawDate = genesis.data.genesis_time;
|
||||
return parseInt(rawDate) + slot * SLOT_TIME;
|
||||
};
|
|
@ -2,6 +2,7 @@ import { useState, useEffect } from "react";
|
|||
|
||||
export type OtterscanConfig = {
|
||||
erigonURL?: string;
|
||||
beaconAPI?: string;
|
||||
assetsURLPrefix?: string;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue