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:
Josh 2021-01-05 14:22:12 -08:00 committed by GitHub
parent a8b5a32b50
commit e5b10d8b7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 3 deletions

View File

@ -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>

View File

@ -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]);

View File

@ -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,
};
}