Skip to content

Commit f5d1230

Browse files
feat: boot progress setup
1 parent 8d73aee commit f5d1230

38 files changed

+1817
-124
lines changed

index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
as="image"
3535
href="./src/assets/frankendancer_logo.svg"
3636
/>
37+
<link
38+
rel="preload"
39+
type="image/svg+xml"
40+
as="image"
41+
href="./src/assets/boot_progress_background.svg"
42+
/>
3743
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
3844
<title>Firedancer</title>
3945
</head>

src/api/atoms.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import type {
2323
BlockEngineUpdate,
2424
VoteBalance,
2525
ScheduleStrategy,
26+
BootProgress,
27+
GossipNetworkStats,
2628
} from "./types";
2729
import { rafAtom } from "../atomUtils";
2830

@@ -74,8 +76,13 @@ export const liveTilePrimaryMetricAtom = atom<
7476

7577
export const tileTimerAtom = atom<number[] | undefined>(undefined);
7678

79+
export const bootProgressAtom = atom<BootProgress | undefined>(undefined);
7780
export const startupProgressAtom = atom<StartupProgress | undefined>(undefined);
7881

82+
export const gossipNetworkStatsAtom = atom<GossipNetworkStats | undefined>(
83+
undefined,
84+
);
85+
7986
export const tpsHistoryAtom = atom<TpsHistory | undefined>(undefined);
8087

8188
export const voteStateAtom = atom<VoteState | undefined>(undefined);

src/api/entities.ts

Lines changed: 195 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ const epochTopicSchema = z.object({
1111
topic: z.literal("epoch"),
1212
});
1313

14+
const gossipTopicSchema = z.object({
15+
topic: z.literal("gossip"),
16+
});
17+
1418
const peersTopicSchema = z.object({
1519
topic: z.literal("peers"),
1620
});
@@ -26,6 +30,7 @@ const blockEngineTopicSchema = z.object({
2630
export const topicSchema = z.discriminatedUnion("topic", [
2731
summaryTopicSchema,
2832
epochTopicSchema,
33+
gossipTopicSchema,
2934
peersTopicSchema,
3035
slotTopicSchema,
3136
blockEngineTopicSchema,
@@ -71,6 +76,9 @@ export const tileTypeSchema = z.enum([
7176
"plugin",
7277
"gui",
7378
"cswtch",
79+
"snaprd",
80+
"snapdc",
81+
"snapin",
7482
]);
7583

7684
export const tileSchema = z.object({
@@ -198,17 +206,17 @@ export const startupProgressSchema = z.object({
198206
downloading_full_snapshot_elapsed_secs: z.number().nullable(),
199207
downloading_full_snapshot_remaining_secs: z.number().nullable(),
200208
downloading_full_snapshot_throughput: z.number().nullable(),
201-
downloading_full_snapshot_total_bytes: z.number().nullable(),
202-
downloading_full_snapshot_current_bytes: z.number().nullable(),
209+
downloading_full_snapshot_total_bytes: z.coerce.number().nullable(),
210+
downloading_full_snapshot_current_bytes: z.coerce.number().nullable(),
203211

204212
// downloading incremental snapshot
205213
downloading_incremental_snapshot_slot: z.number().nullable(),
206214
downloading_incremental_snapshot_peer: z.string().nullable(),
207215
downloading_incremental_snapshot_elapsed_secs: z.number().nullable(),
208216
downloading_incremental_snapshot_remaining_secs: z.number().nullable(),
209217
downloading_incremental_snapshot_throughput: z.number().nullable(),
210-
downloading_incremental_snapshot_total_bytes: z.number().nullable(),
211-
downloading_incremental_snapshot_current_bytes: z.number().nullable(),
218+
downloading_incremental_snapshot_total_bytes: z.coerce.number().nullable(),
219+
downloading_incremental_snapshot_current_bytes: z.coerce.number().nullable(),
212220

213221
// processing ledger
214222
ledger_slot: z.number().nullable(),
@@ -219,6 +227,148 @@ export const startupProgressSchema = z.object({
219227
waiting_for_supermajority_stake_percent: z.number().nullable(),
220228
});
221229

230+
export const bootPhaseSchema = z.enum([
231+
"joining_gossip",
232+
"loading_full_snapshot",
233+
"loading_incr_snapshot",
234+
"catching_up",
235+
"running",
236+
]);
237+
238+
export const BootPhaseEnum = bootPhaseSchema.enum;
239+
240+
export const bootProgressSchema = z.object({
241+
phase: bootPhaseSchema,
242+
total_elapsed: z.number(),
243+
244+
// joining_gossip
245+
joining_gossip_elapsed: z.number().nullable(),
246+
247+
// loading_full_snapshot
248+
loading_full_snapshot_reset_cnt: z.number().nullable().optional(),
249+
loading_full_snapshot_slot: z.number().nullable().optional(),
250+
loading_full_snapshot_peer: z.string().nullable().optional(),
251+
loading_full_snapshot_peer_identity: z.string().nullable().optional(),
252+
loading_full_snapshot_total_bytes: z.coerce.number().nullable().optional(),
253+
loading_full_snapshot_elapsed: z.number().nullable().optional(),
254+
loading_full_snapshot_read_bytes: z.coerce.number().nullable().optional(),
255+
loading_full_snapshot_read_throughput: z.number().nullable().optional(),
256+
loading_full_snapshot_current_bytes: z.coerce.number().nullable().optional(),
257+
loading_full_snapshot_read_remaining: z.number().nullable().optional(),
258+
loading_full_snapshot_read_elapsed: z.number().nullable().optional(),
259+
loading_full_snapshot_read_path: z.string().nullable().optional(),
260+
loading_full_snapshot_decompress_bytes: z.number().nullable().optional(),
261+
loading_full_snapshot_decompress_elapsed: z.number().nullable().optional(),
262+
loading_full_snapshot_decompress_throughput: z.number().nullable().optional(),
263+
loading_full_snapshot_decompress_compressed_bytes: z.coerce
264+
.number()
265+
.nullable()
266+
.optional(),
267+
loading_full_snapshot_decompress_decompressed_bytes: z.coerce
268+
.number()
269+
.nullable()
270+
.optional(),
271+
loading_full_snapshot_decompress_remaining: z.number().nullable().optional(),
272+
loading_full_snapshot_insert_bytes: z.coerce.number().nullable().optional(),
273+
loading_full_snapshot_insert_throughput: z.number().nullable().optional(),
274+
loading_full_snapshot_insert_remaining: z.number().nullable().optional(),
275+
loading_full_snapshot_insert_path: z.string().nullable().optional(),
276+
loading_full_snapshot_insert_elapsed: z.number().nullable().optional(),
277+
loading_full_snapshot_insert_accounts_throughput: z
278+
.number()
279+
.nullable()
280+
.optional(),
281+
loading_full_snapshot_insert_accounts_current: z
282+
.number()
283+
.nullable()
284+
.optional(),
285+
286+
// loading_incremental_snapshot
287+
loading_incremental_snapshot_reset_cnt: z.number().nullable().optional(),
288+
loading_incremental_snapshot_peer_identity: z.string().nullable().optional(),
289+
loading_incremental_snapshot_slot: z.number().nullable().optional(),
290+
loading_incremental_snapshot_peer: z.string().nullable().optional(),
291+
loading_incremental_snapshot_total_bytes: z.coerce
292+
.number()
293+
.nullable()
294+
.optional(),
295+
loading_incremental_snapshot_elapsed: z.number().nullable().optional(),
296+
loading_incremental_snapshot_read_bytes: z.coerce
297+
.number()
298+
.nullable()
299+
.optional(),
300+
loading_incremental_snapshot_read_elapsed: z.number().nullable().optional(),
301+
loading_incremental_snapshot_read_throughput: z
302+
.number()
303+
.nullable()
304+
.optional(),
305+
loading_incremental_snapshot_read_remaining: z.number().nullable().optional(),
306+
loading_incremental_snapshot_read_path: z.string().nullable().optional(),
307+
loading_incremental_snapshot_current_bytes: z.coerce
308+
.number()
309+
.nullable()
310+
.optional(),
311+
loading_incremental_snapshot_decompress_bytes: z.coerce
312+
.number()
313+
.nullable()
314+
.optional(),
315+
316+
loading_incremental_snapshot_decompress_elapsed: z
317+
.number()
318+
.nullable()
319+
.optional(),
320+
loading_incremental_snapshot_decompress_throughput: z
321+
.number()
322+
.nullable()
323+
.optional(),
324+
loading_incremental_snapshot_decompress_compressed_bytes: z.coerce
325+
.number()
326+
.nullable()
327+
.optional(),
328+
loading_incremental_snapshot_decompress_decompressed_bytes: z.coerce
329+
.number()
330+
.nullable()
331+
.optional(),
332+
loading_incremental_snapshot_decompress_remaining: z
333+
.number()
334+
.nullable()
335+
.optional(),
336+
loading_incremental_snapshot_insert_bytes: z.coerce
337+
.number()
338+
.nullable()
339+
.optional(),
340+
loading_incremental_snapshot_insert_elapsed: z.number().nullable().optional(),
341+
loading_incremental_snapshot_insert_throughput: z
342+
.number()
343+
.nullable()
344+
.optional(),
345+
loading_incremental_snapshot_insert_remaining: z
346+
.number()
347+
.nullable()
348+
.optional(),
349+
loading_incremental_snapshot_insert_path: z.string().nullable().optional(),
350+
loading_incremental_snapshot_insert_accounts_throughput: z
351+
.number()
352+
.nullable()
353+
.optional(),
354+
loading_incremental_snapshot_insert_accounts_current: z
355+
.number()
356+
.nullable()
357+
.optional(),
358+
359+
// catching_up
360+
catching_up_elapsed: z.number().nullable().optional(),
361+
catching_up_min_turbine_slot: z.number().nullable().optional(),
362+
catching_up_max_turbine_slot: z.number().nullable().optional(),
363+
catching_up_min_repair_slot: z.number().nullable().optional(),
364+
catching_up_max_repair_slot: z.number().nullable().optional(),
365+
catching_up_max_replay_slot: z.number().nullable().optional(),
366+
catching_up_first_turbine_slot: z.number().nullable().optional(),
367+
catching_up_latest_turbine_slot: z.number().nullable().optional(),
368+
catching_up_latest_repair_slot: z.number().nullable().optional(),
369+
catching_up_latest_replay_slot: z.number().nullable().optional(),
370+
});
371+
222372
export const slotTransactionsSchema = z.object({
223373
start_timestamp_nanos: z.coerce.bigint(),
224374
target_end_timestamp_nanos: z.coerce.bigint(),
@@ -371,6 +521,10 @@ export const summarySchema = z.discriminatedUnion("key", [
371521
key: z.literal("startup_progress"),
372522
value: startupProgressSchema,
373523
}),
524+
summaryTopicSchema.extend({
525+
key: z.literal("boot_progress"),
526+
value: bootProgressSchema,
527+
}),
374528
summaryTopicSchema.extend({
375529
key: z.literal("tps_history"),
376530
value: tpsHistorySchema,
@@ -408,6 +562,43 @@ export const epochSchema = z.discriminatedUnion("key", [
408562
}),
409563
]);
410564

565+
const gossipNetworkHealthSchema = z.object({
566+
rx_push_pct: z.number().optional(),
567+
duplicate_pct: z.number().optional(),
568+
bad_pct: z.number().optional(),
569+
pull_already_known_pct: z.number().optional(),
570+
total_stake: z.coerce.bigint(),
571+
total_peers: z.coerce.bigint(),
572+
connected_stake: z.coerce.bigint(),
573+
connected_peers: z.number(),
574+
});
575+
576+
const gossipNetworkTrafficSchema = z.object({
577+
total_throughput: z.number().optional(),
578+
peer_names: z.string().array(),
579+
peer_throughputs: z.number().array().optional(),
580+
});
581+
582+
const gossipStorageUtilSchema = z.object({
583+
total_bytes: z.coerce.number(),
584+
peer_names: z.string().array(),
585+
peer_bytes: z.number().array(),
586+
});
587+
588+
export const gossipNetworkStatsSchema = z.object({
589+
health: gossipNetworkHealthSchema,
590+
ingress: gossipNetworkTrafficSchema,
591+
egress: gossipNetworkTrafficSchema,
592+
storage: gossipStorageUtilSchema,
593+
});
594+
595+
export const gossipSchema = z.discriminatedUnion("key", [
596+
gossipTopicSchema.extend({
597+
key: z.literal("network_stats"),
598+
value: gossipNetworkStatsSchema,
599+
}),
600+
]);
601+
411602
const peerUpdateGossipSchema = z.object({
412603
wallclock: z.number(),
413604
shred_version: z.number(),

src/api/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ import type {
4040
slotTransactionsSchema,
4141
voteBalanceSchema,
4242
scheduleStrategySchema,
43+
bootPhaseSchema,
44+
bootProgressSchema,
45+
gossipNetworkStatsSchema,
4346
} from "./entities";
4447

4548
export type Client = z.infer<typeof clientSchema>;
@@ -98,10 +101,14 @@ export type TileType = z.infer<typeof tileTypeSchema>;
98101

99102
export type TileTimer = z.infer<typeof tileTimerSchema>;
100103

104+
export type BootProgress = z.infer<typeof bootProgressSchema>;
105+
101106
export type StartupProgress = z.infer<typeof startupProgressSchema>;
102107

103108
export type StartupPhase = z.infer<typeof startupPhaseSchema>;
104109

110+
export type BootPhase = z.infer<typeof bootPhaseSchema>;
111+
105112
export type TpsHistory = z.infer<typeof tpsHistorySchema>;
106113

107114
export type VoteState = z.infer<typeof voteStateSchema>;
@@ -114,6 +121,8 @@ export type Epoch = z.infer<typeof epochNewSchema>;
114121

115122
export type SlotLevel = z.infer<typeof slotLevelSchema>;
116123

124+
export type GossipNetworkStats = z.infer<typeof gossipNetworkStatsSchema>;
125+
117126
export interface Peer extends z.infer<typeof peerUpdateSchema> {
118127
removed?: boolean;
119128
}

src/api/useSetAtomWsData.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ import {
2020
voteStateAtom,
2121
voteBalanceAtom,
2222
scheduleStrategyAtom,
23+
bootProgressAtom,
24+
gossipNetworkStatsAtom,
2325
} from "./atoms";
2426
import {
2527
blockEngineSchema,
2628
epochSchema,
29+
gossipSchema,
2730
peersSchema,
2831
slotSchema,
2932
summarySchema,
@@ -120,6 +123,7 @@ export function useSetAtomWsData() {
120123
setTileTimer(value);
121124
}, tileTimerDebounceMs);
122125

126+
const setBootProgress = useSetAtom(bootProgressAtom);
123127
const setStartupProgress = useSetAtom(startupProgressAtom);
124128

125129
const setTpsHistory = useSetAtom(tpsHistoryAtom);
@@ -135,6 +139,8 @@ export function useSetAtomWsData() {
135139

136140
const setSlotStatus = useSetAtom(setSlotStatusAtom);
137141

142+
const setGossipNetworkStats = useSetAtom(gossipNetworkStatsAtom);
143+
138144
const addPeers = useSetAtom(addPeersAtom);
139145
const updatePeers = useSetAtom(updatePeersAtom);
140146
const removePeers = useSetAtom(removePeersAtom);
@@ -226,6 +232,10 @@ export function useSetAtomWsData() {
226232
setDbTileTimer(value);
227233
break;
228234
}
235+
case "boot_progress": {
236+
setBootProgress(value);
237+
break;
238+
}
229239
case "startup_progress": {
230240
setStartupProgress(value);
231241
break;
@@ -260,6 +270,14 @@ export function useSetAtomWsData() {
260270
setEpoch(value);
261271
break;
262272
}
273+
} else if (topic === "gossip") {
274+
const { key, value } = gossipSchema.parse(msg);
275+
switch (key) {
276+
case "network_stats": {
277+
setGossipNetworkStats(value);
278+
break;
279+
}
280+
}
263281
} else if (topic === "peers") {
264282
const { value } = peersSchema.parse(msg);
265283
addPeers(value.add);
Lines changed: 3 additions & 0 deletions
Loading

src/atoms.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const clientAtom = atom(() => {
3535
});
3636

3737
export const containerElAtom = atom<HTMLDivElement | null>();
38+
export const bootProgressContainerElAtom = atom<HTMLDivElement | null>();
3839

3940
const _epochsAtom = atomWithImmer<Epoch[]>([]);
4041
export const epochAtom = atom(

0 commit comments

Comments
 (0)