Skip to content

Commit 1f40f12

Browse files
chore: check server time to delete shred slots
1 parent 3cca158 commit 1f40f12

File tree

20 files changed

+569
-27
lines changed

20 files changed

+569
-27
lines changed

src/api/atoms.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import type {
3030
GossipPeersRowsUpdate,
3131
GossipPeersCellUpdate,
3232
ServerTimeNanos,
33+
LiveNetworkMetrics,
34+
TileMetrics,
3335
} from "./types";
3436
import { rafAtom } from "../atomUtils";
3537

@@ -72,6 +74,10 @@ export const estimatedSlotDurationAtom = atom<
7274

7375
export const estimatedTpsAtom = atom<EstimatedTps | undefined>(undefined);
7476

77+
export const liveNetworkMetricsAtom = atom<LiveNetworkMetrics | undefined>(
78+
undefined,
79+
);
80+
7581
export const liveTxnWaterfallAtom = rafAtom<LiveTxnWaterfall | undefined>(
7682
undefined,
7783
);
@@ -80,6 +86,8 @@ export const liveTilePrimaryMetricAtom = atom<
8086
LiveTilePrimaryMetric | undefined
8187
>(undefined);
8288

89+
export const liveTileMetricsAtom = atom<TileMetrics | undefined>(undefined);
90+
8391
export const tileTimerAtom = atom<number[] | undefined>(undefined);
8492

8593
export const bootProgressAtom = atom<BootProgress | undefined>(undefined);

src/api/consts.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
export const estimatedTpsDebounceMs = 400;
22
export const liveMetricsDebounceMs = 100;
3+
export const liveTileMetricsDebounceMs = 130;
4+
export const liveNetworkMetricsDebounceMs = 130;
35
export const waterfallDebounceMs = 100;
46
export const tileTimerDebounceMs = 25;
7+
export const gossipNetworkDebounceMs = 300;
8+
export const gossipPeerSizeDebounceMs = 1_000;

src/api/entities.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export const resetSlotSchema = z.number().nullable();
128128
export const storageSlotSchema = z.number().nullable();
129129
export const voteSlotSchema = z.number();
130130
export const slotCaughtUpSchema = z.number().nullable();
131+
export const activeForkCountSchema = z.number();
131132

132133
export const estimatedSlotDurationSchema = z.number();
133134

@@ -503,6 +504,10 @@ export const summarySchema = z.discriminatedUnion("key", [
503504
key: z.literal("slot_caught_up"),
504505
value: slotCaughtUpSchema,
505506
}),
507+
summaryTopicSchema.extend({
508+
key: z.literal("active_fork_count"),
509+
value: activeForkCountSchema,
510+
}),
506511
summaryTopicSchema.extend({
507512
key: z.literal("estimated_slot_duration_nanos"),
508513
value: estimatedSlotDurationSchema,

src/api/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ import type {
5858
gossipMessageStatsSchema,
5959
schedulerCountsSchema,
6060
serverTimeNanosSchema,
61+
liveNetworkMetricsSchema,
62+
tileMetricsSchema,
6163
} from "./entities";
6264

6365
export type Client = z.infer<typeof clientSchema>;
@@ -105,12 +107,16 @@ export type EstimatedSlotDuration = z.infer<typeof estimatedSlotDurationSchema>;
105107

106108
export type EstimatedTps = z.infer<typeof estimatedTpsSchema>;
107109

110+
export type LiveNetworkMetrics = z.infer<typeof liveNetworkMetricsSchema>;
111+
108112
export type LiveTxnWaterfall = z.infer<typeof liveTxnWaterfallSchema>;
109113

110114
export type LiveTilePrimaryMetric = z.infer<typeof liveTilePrimaryMetricSchema>;
111115

112116
export type TilePrimaryMetric = z.infer<typeof tilePrimaryMetricSchema>;
113117

118+
export type TileMetrics = z.infer<typeof tileMetricsSchema>;
119+
114120
export type TxnWaterfallIn = z.infer<typeof txnWaterfallInSchema>;
115121
export type TxnWaterfallOut = z.infer<typeof txnWaterfallOutSchema>;
116122
export type TxnWaterfall = z.infer<typeof txnWaterfallSchema>;

src/api/useSetAtomWsData.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import {
2828
gossipPeersRowsUpdateAtom,
2929
gossipPeersCellUpdateAtom,
3030
serverTimeNanosAtom,
31+
liveNetworkMetricsAtom,
32+
liveTileMetricsAtom,
3133
} from "./atoms";
3234
import {
3335
blockEngineSchema,
@@ -58,12 +60,14 @@ import type {
5860
EstimatedTps,
5961
GossipNetworkStats,
6062
GossipPeersSize,
63+
LiveNetworkMetrics,
6164
LiveTilePrimaryMetric,
6265
LiveTxnWaterfall,
6366
Peer,
6467
PeerRemove,
6568
RepairSlot,
6669
SlotResponse,
70+
TileMetrics,
6771
TurbineSlot,
6872
} from "./types";
6973
import { useDebouncedCallback, useThrottledCallback } from "use-debounce";
@@ -72,7 +76,11 @@ import { useServerMessages } from "./ws/utils";
7276
import { DateTime } from "luxon";
7377
import {
7478
estimatedTpsDebounceMs,
79+
gossipNetworkDebounceMs,
80+
gossipPeerSizeDebounceMs,
7581
liveMetricsDebounceMs,
82+
liveNetworkMetricsDebounceMs,
83+
liveTileMetricsDebounceMs,
7684
tileTimerDebounceMs,
7785
waterfallDebounceMs,
7886
} from "./consts";
@@ -133,6 +141,19 @@ export function useSetAtomWsData() {
133141
setEstimatedTps(value);
134142
}, estimatedTpsDebounceMs);
135143

144+
const setLiveNetworkMetrics = useSetAtom(liveNetworkMetricsAtom);
145+
const setDbLiveNetworkMetrics = useThrottledCallback(
146+
(value?: LiveNetworkMetrics) => {
147+
setLiveNetworkMetrics(value);
148+
},
149+
liveNetworkMetricsDebounceMs,
150+
);
151+
152+
const setLiveTileMetrics = useSetAtom(liveTileMetricsAtom);
153+
const setDbLiveTileMetrics = useThrottledCallback((value?: TileMetrics) => {
154+
setLiveTileMetrics(value);
155+
}, liveTileMetricsDebounceMs);
156+
136157
const setLivePrimaryMetrics = useSetAtom(liveTilePrimaryMetricAtom);
137158
const setDbLivePrimaryMetrics = useThrottledCallback(
138159
(value?: LiveTilePrimaryMetric) => {
@@ -178,15 +199,15 @@ export function useSetAtomWsData() {
178199
(value?: GossipNetworkStats) => {
179200
setGossipNetworkStats(value);
180201
},
181-
300,
202+
gossipNetworkDebounceMs,
182203
);
183204

184205
const setGossipPeersSize = useSetAtom(gossipPeersSizeAtom);
185206
const setDbGossipPeersSize = useThrottledCallback(
186207
(value?: GossipPeersSize) => {
187208
setGossipPeersSize(value);
188209
},
189-
1_000,
210+
gossipPeerSizeDebounceMs,
190211
);
191212
const setGossipPeersRows = useSetAtom(gossipPeersRowsUpdateAtom);
192213
const setGossipPeersCells = useSetAtom(gossipPeersCellUpdateAtom);
@@ -389,6 +410,13 @@ export function useSetAtomWsData() {
389410
setServerTimeNanos(value);
390411
break;
391412
}
413+
case "live_network_metrics": {
414+
setDbLiveNetworkMetrics(value);
415+
break;
416+
}
417+
case "live_tile_metrics":
418+
setDbLiveTileMetrics(value);
419+
break;
392420
case "root_slot":
393421
case "optimistically_confirmed_slot":
394422
case "estimated_slot":
@@ -398,8 +426,7 @@ export function useSetAtomWsData() {
398426
case "storage_slot":
399427
case "vote_slot":
400428
case "slot_caught_up":
401-
case "live_network_metrics":
402-
case "live_tile_metrics":
429+
case "active_fork_count":
403430
break;
404431
}
405432
} else if (topic === "epoch") {

src/clockUtils.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
type Sub = (now: number, dt: number) => void;
22

3-
export function clockSub(intervalMs: number) {
3+
export function clockSub(_intervalMs: number) {
44
const subs = new Set<Sub>();
55
let id: number | null = null;
66
let last = performance.now();
7+
let intervalMs = _intervalMs;
78

8-
function startChartClock() {
9+
function startChartClock(newIntervalMs?: number) {
910
if (id == null) {
1011
stopChartClock();
1112
}
13+
if (newIntervalMs !== undefined) {
14+
stopChartClock();
15+
intervalMs = newIntervalMs;
16+
}
1217

1318
const loop = () => {
1419
const now = performance.now();
@@ -37,5 +42,5 @@ export function clockSub(intervalMs: number) {
3742

3843
startChartClock();
3944

40-
return { subscribeClock, stopChartClock };
45+
return { subscribeClock, stopChartClock, startChartClock };
4146
}

src/colors.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,6 @@ export const slotsListFutureSlotColor = "#878787";
283283
export const slotsListCurrentSlotBoxShadowColor = "rgba(191, 135, 253, 0.13)";
284284
export const slotsListCurrentSlotNumberBackgroundColor = "#283551";
285285
export const slotsListNextLeaderProgressBarColor = "#37a4bc";
286+
287+
// Tile charts
288+
export const tileChartDarkBackground = "#0000001F";
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const networkProtocols = [
2+
"turbine",
3+
"gossip",
4+
"tpu",
5+
"repair",
6+
"metrics",
7+
];
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { useAtomValue } from "jotai";
2+
import { liveNetworkMetricsAtom } from "../../../api/atoms";
3+
import Card from "../../../components/Card";
4+
import { Flex, Table, Text } from "@radix-ui/themes";
5+
import tableStyles from "../../Gossip/table.module.css";
6+
import { useEmaValue } from "../../../hooks/useEma";
7+
import { networkProtocols } from "./consts";
8+
import { formatBytesAsBits } from "../../../utils";
9+
import { Bars } from "../../StartupProgress/Firedancer/Bars";
10+
import TileSparkLine from "../SlotPerformance/TileSparkLine";
11+
import { headerGap } from "../../Gossip/consts";
12+
import type { CSSProperties } from "react";
13+
import styles from "./liveNetworkMetrics.module.css";
14+
import { sum } from "lodash";
15+
import { tileChartDarkBackground } from "../../../colors";
16+
17+
const chartHeight = 18;
18+
19+
export default function LiveNetworkMetrics() {
20+
const liveNetworkMetrics = useAtomValue(liveNetworkMetricsAtom);
21+
if (!liveNetworkMetrics) return;
22+
23+
return (
24+
<Flex wrap="wrap" gap="4">
25+
<NetworkMetricsCard metrics={liveNetworkMetrics.ingress} type="Ingress" />
26+
<NetworkMetricsCard metrics={liveNetworkMetrics.egress} type="Egress" />
27+
</Flex>
28+
);
29+
}
30+
31+
interface NetworkMetricsCardProps {
32+
metrics: number[];
33+
type: "Ingress" | "Egress";
34+
}
35+
36+
function NetworkMetricsCard({ metrics, type }: NetworkMetricsCardProps) {
37+
return (
38+
<Card style={{ flexGrow: 1 }}>
39+
<Flex direction="column" height="100%" gap={headerGap}>
40+
<Text className={tableStyles.headerText}>Network {type}</Text>
41+
<Table.Root
42+
variant="ghost"
43+
className={tableStyles.root}
44+
size="1"
45+
style={{ "--bar-height": `${chartHeight}px` } as CSSProperties}
46+
>
47+
<Table.Header>
48+
<Table.Row>
49+
<Table.ColumnHeaderCell width="60px">
50+
Protocol
51+
</Table.ColumnHeaderCell>
52+
<Table.ColumnHeaderCell align="right" width="80px">
53+
Current
54+
</Table.ColumnHeaderCell>
55+
<Table.ColumnHeaderCell
56+
minWidth={{
57+
xl: "250px",
58+
lg: "160px",
59+
md: "100px",
60+
initial: "60px",
61+
}}
62+
>
63+
Utilization
64+
</Table.ColumnHeaderCell>
65+
<Table.ColumnHeaderCell
66+
align="right"
67+
width={{
68+
xl: "240px",
69+
lg: "200px",
70+
md: "100px",
71+
initial: "200px",
72+
}}
73+
>
74+
History (1m)
75+
</Table.ColumnHeaderCell>
76+
</Table.Row>
77+
</Table.Header>
78+
79+
<Table.Body>
80+
{metrics.map((value, i) => (
81+
<TableRow key={i} value={value} idx={i} />
82+
))}
83+
<TableRow
84+
value={sum(metrics)}
85+
label="Total"
86+
className={styles.totalRow}
87+
/>
88+
</Table.Body>
89+
</Table.Root>
90+
</Flex>
91+
</Card>
92+
);
93+
}
94+
95+
const maxValue = 100_000_000;
96+
97+
interface TableRowProps {
98+
value: number;
99+
idx?: number;
100+
label?: string;
101+
}
102+
103+
function TableRow({
104+
value,
105+
idx,
106+
label,
107+
...props
108+
}: TableRowProps & Table.RootProps) {
109+
const emaValue = useEmaValue(value);
110+
const formattedValue = formatBytesAsBits(emaValue);
111+
112+
return (
113+
<Table.Row {...props}>
114+
<Table.RowHeaderCell>
115+
{label ?? networkProtocols[idx ?? -1]}
116+
</Table.RowHeaderCell>
117+
<Table.Cell align="right">
118+
{formattedValue.value} {formattedValue.unit}
119+
</Table.Cell>
120+
<Table.Cell className={styles.chart}>
121+
<Flex align="center">
122+
<Bars value={emaValue} max={maxValue} barWidth={2} />
123+
</Flex>
124+
</Table.Cell>
125+
<Table.Cell className={styles.chart}>
126+
<TileSparkLine
127+
value={Math.min(1, emaValue / maxValue)}
128+
background={tileChartDarkBackground}
129+
windowMs={60_000}
130+
height={chartHeight}
131+
updateIntervalMs={500}
132+
tickMs={1_000}
133+
/>
134+
</Table.Cell>
135+
</Table.Row>
136+
);
137+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.chart {
2+
padding-top: 0;
3+
padding-bottom: 0;
4+
vertical-align: middle;
5+
}

0 commit comments

Comments
 (0)