explorer: display block time on cluster stats (#14439)
* explorer: display block time on cluster stats * interpolate blocktime values between fetches * prevent time from going backwards
This commit is contained in:
parent
a8b5a32b50
commit
e5b10d8b7e
|
@ -10,6 +10,7 @@ import {
|
|||
import { slotsToHumanString } from "utils";
|
||||
import { useCluster } from "providers/cluster";
|
||||
import { TpsCard } from "components/TpsCard";
|
||||
import { displayTimestamp } from "utils/date";
|
||||
|
||||
const CLUSTER_STATS_TIMEOUT = 10000;
|
||||
|
||||
|
@ -52,7 +53,12 @@ function StatsCardBody() {
|
|||
return <StatsNotReady error={error} />;
|
||||
}
|
||||
|
||||
const { avgSlotTime_1h, avgSlotTime_1min, epochInfo } = dashboardInfo;
|
||||
const {
|
||||
avgSlotTime_1h,
|
||||
avgSlotTime_1min,
|
||||
epochInfo,
|
||||
blockTime,
|
||||
} = dashboardInfo;
|
||||
const hourlySlotTime = Math.round(1000 * avgSlotTime_1h);
|
||||
const averageSlotTime = Math.round(1000 * avgSlotTime_1min);
|
||||
const { slotIndex, slotsInEpoch } = epochInfo;
|
||||
|
@ -80,6 +86,14 @@ function StatsCardBody() {
|
|||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{blockTime && (
|
||||
<tr>
|
||||
<td className="w-100">Block time</td>
|
||||
<td className="text-lg-right text-monospace">
|
||||
{displayTimestamp(blockTime)}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
<tr>
|
||||
<td className="w-100">Slot time (1min average)</td>
|
||||
<td className="text-lg-right text-monospace">{averageSlotTime}ms</td>
|
||||
|
|
|
@ -18,6 +18,7 @@ export const SAMPLE_HISTORY_HOURS = 6;
|
|||
export const PERFORMANCE_SAMPLE_INTERVAL = 60000;
|
||||
export const TRANSACTION_COUNT_INTERVAL = 5000;
|
||||
export const EPOCH_INFO_INTERVAL = 2000;
|
||||
export const BLOCK_TIME_INTERVAL = 5000;
|
||||
export const LOADING_TIMEOUT = 10000;
|
||||
|
||||
export enum ClusterStatsStatus {
|
||||
|
@ -89,6 +90,7 @@ export function SolanaClusterStatsProvider({ children }: Props) {
|
|||
if (!active || !url) return;
|
||||
|
||||
const connection = new Connection(url);
|
||||
let lastSlot: number | null = null;
|
||||
|
||||
const getPerformanceSamples = async () => {
|
||||
try {
|
||||
|
@ -148,6 +150,7 @@ export function SolanaClusterStatsProvider({ children }: Props) {
|
|||
const getEpochInfo = async () => {
|
||||
try {
|
||||
const epochInfo = await connection.getEpochInfo();
|
||||
lastSlot = epochInfo.absoluteSlot;
|
||||
dispatchDashboardInfo({
|
||||
type: DashboardInfoActionType.SetEpochInfo,
|
||||
data: epochInfo,
|
||||
|
@ -164,6 +167,25 @@ export function SolanaClusterStatsProvider({ children }: Props) {
|
|||
}
|
||||
};
|
||||
|
||||
const getBlockTime = async () => {
|
||||
if (lastSlot) {
|
||||
try {
|
||||
const blockTime = await connection.getBlockTime(lastSlot);
|
||||
if (blockTime !== null) {
|
||||
dispatchDashboardInfo({
|
||||
type: DashboardInfoActionType.SetLastBlockTime,
|
||||
data: {
|
||||
slot: lastSlot,
|
||||
blockTime: blockTime * 1000,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
// let this fail gracefully
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const performanceInterval = setInterval(
|
||||
getPerformanceSamples,
|
||||
PERFORMANCE_SAMPLE_INTERVAL
|
||||
|
@ -173,15 +195,20 @@ export function SolanaClusterStatsProvider({ children }: Props) {
|
|||
TRANSACTION_COUNT_INTERVAL
|
||||
);
|
||||
const epochInfoInterval = setInterval(getEpochInfo, EPOCH_INFO_INTERVAL);
|
||||
const blockTimeInterval = setInterval(getBlockTime, BLOCK_TIME_INTERVAL);
|
||||
|
||||
getPerformanceSamples();
|
||||
getTransactionCount();
|
||||
getEpochInfo();
|
||||
(async () => {
|
||||
await getEpochInfo();
|
||||
await getBlockTime();
|
||||
})();
|
||||
|
||||
return () => {
|
||||
clearInterval(performanceInterval);
|
||||
clearInterval(transactionCountInterval);
|
||||
clearInterval(epochInfoInterval);
|
||||
clearInterval(blockTimeInterval);
|
||||
};
|
||||
}, [active, cluster, url]);
|
||||
|
||||
|
|
|
@ -6,11 +6,19 @@ export type DashboardInfo = {
|
|||
avgSlotTime_1h: number;
|
||||
avgSlotTime_1min: number;
|
||||
epochInfo: EpochInfo;
|
||||
blockTime?: number;
|
||||
lastBlockTime?: BlockTimeInfo;
|
||||
};
|
||||
|
||||
export type BlockTimeInfo = {
|
||||
blockTime: number;
|
||||
slot: number;
|
||||
};
|
||||
|
||||
export enum DashboardInfoActionType {
|
||||
SetPerfSamples,
|
||||
SetEpochInfo,
|
||||
SetLastBlockTime,
|
||||
SetError,
|
||||
Reset,
|
||||
}
|
||||
|
@ -35,17 +43,32 @@ export type DashboardInfoActionSetError = {
|
|||
data: string;
|
||||
};
|
||||
|
||||
export type DashboardInfoActionSetLastBlockTime = {
|
||||
type: DashboardInfoActionType.SetLastBlockTime;
|
||||
data: BlockTimeInfo;
|
||||
};
|
||||
|
||||
export type DashboardInfoAction =
|
||||
| DashboardInfoActionSetPerfSamples
|
||||
| DashboardInfoActionSetEpochInfo
|
||||
| DashboardInfoActionReset
|
||||
| DashboardInfoActionSetError;
|
||||
| DashboardInfoActionSetError
|
||||
| DashboardInfoActionSetLastBlockTime;
|
||||
|
||||
export function dashboardInfoReducer(
|
||||
state: DashboardInfo,
|
||||
action: DashboardInfoAction
|
||||
) {
|
||||
switch (action.type) {
|
||||
case DashboardInfoActionType.SetLastBlockTime: {
|
||||
const blockTime = state.blockTime || action.data.blockTime;
|
||||
return {
|
||||
...state,
|
||||
lastBlockTime: action.data,
|
||||
blockTime,
|
||||
};
|
||||
}
|
||||
|
||||
case DashboardInfoActionType.SetPerfSamples: {
|
||||
if (action.data.length < 1) {
|
||||
return state;
|
||||
|
@ -85,10 +108,25 @@ export function dashboardInfoReducer(
|
|||
? ClusterStatsStatus.Ready
|
||||
: ClusterStatsStatus.Loading;
|
||||
|
||||
let blockTime = state.blockTime;
|
||||
|
||||
// interpolate blocktime based on last known blocktime and average slot time
|
||||
if (
|
||||
state.lastBlockTime &&
|
||||
state.avgSlotTime_1h !== 0 &&
|
||||
action.data.absoluteSlot >= state.lastBlockTime.slot
|
||||
) {
|
||||
blockTime =
|
||||
state.lastBlockTime.blockTime +
|
||||
(action.data.absoluteSlot - state.lastBlockTime.slot) *
|
||||
Math.floor(state.avgSlotTime_1h * 1000);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
epochInfo: action.data,
|
||||
status,
|
||||
blockTime,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue