Skip to content

Commit 1f92e11

Browse files
committed
add income to cu chart
1 parent 34532de commit 1f92e11

File tree

10 files changed

+218
-45
lines changed

10 files changed

+218
-45
lines changed

src/features/LeaderSchedule/Slots/SlotCardGrid.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ function getRowValues(publish: SlotPublish): RowValues {
219219
const computeUnits = fixValue(publish?.compute_units ?? 0);
220220
const computeUnitsPct =
221221
publish.compute_units != null
222-
? (publish.compute_units / 48_000_000) * 100
222+
? (publish.compute_units / (publish.max_compute_units ?? 48_000_000)) *
223+
100
223224
: 0;
224225

225226
return {

src/features/Overview/SlotPerformance/ComputeUnitsCard/Chart.tsx

Lines changed: 110 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ interface ChartData {
5151
timestampNanos: number;
5252
computeUnits: number;
5353
activeBankCount: number;
54+
priority_fees_lamports: number;
55+
tips_lamports: number;
5456
}
5557

5658
const minRangeNanos = 50_000;
@@ -60,9 +62,9 @@ const wheelScrollSpeed = 1 / 3_000;
6062
const smNanosThreshold = 5_000_000;
6163
const mdNanosThreshold = 50_000_000;
6264
const _segmentColors = [
65+
{ fill: "#1E9C50", opacity: 0 },
6366
{ fill: "#1E9C50", opacity: 0.15 },
6467
{ fill: "#AE5511", opacity: 0.15 },
65-
{ fill: "#CF321D", opacity: 0.15 },
6668
{ fill: "#F40505", opacity: 0.15 },
6769
{ fill: "#F40505", opacity: 0.2 },
6870
];
@@ -71,9 +73,7 @@ const getSegmentColor = (index: number) => {
7173
};
7274
const cuAxisId = "computeUnits";
7375
const bankCountAxisId = "activeBankCount";
74-
const defaultCuTicks = [
75-
8_000_000, 16_000_000, 24_000_000, 32_000_000, 40_000_000, 48_000_000,
76-
];
76+
const incomeAxisId = "income";
7777

7878
const cusPerNs = 1 / 8;
7979
const tickLabelWidth = 110;
@@ -103,6 +103,18 @@ function getChartData(computeUnits: ComputeUnits): ChartData[] {
103103
: -computeUnits.txn_max_compute_units[txn_idx] +
104104
computeUnits.txn_compute_units_consumed[txn_idx]
105105
: 0;
106+
const priority_fee =
107+
!event.start &&
108+
computeUnits.txn_landed[txn_idx] &&
109+
computeUnits.txn_error_code[txn_idx] === 0
110+
? Number(computeUnits.txn_priority_fee[txn_idx])
111+
: 0;
112+
const tip =
113+
!event.start &&
114+
computeUnits.txn_landed[txn_idx] &&
115+
computeUnits.txn_error_code[txn_idx] === 0
116+
? Number(computeUnits.txn_tips[txn_idx])
117+
: 0;
106118

107119
const prev = chartData[chartData.length - 1];
108120
activeBanks[computeUnits.txn_bank_idx[txn_idx]] = event.start;
@@ -113,18 +125,30 @@ function getChartData(computeUnits: ComputeUnits): ChartData[] {
113125
if (i > 0 && events[i - 1].timestampNanos === event.timestampNanos) {
114126
prev.computeUnits += cus_delta;
115127
prev.activeBankCount = activeBankCount;
128+
prev.priority_fees_lamports += priority_fee;
129+
prev.tips_lamports += tip;
116130
} else {
117131
chartData.push({
118132
timestampNanos: Number(
119133
event.timestampNanos - computeUnits.start_timestamp_nanos,
120134
),
121135
computeUnits: prev.computeUnits + cus_delta,
122136
activeBankCount,
137+
priority_fees_lamports: prev.priority_fees_lamports + priority_fee,
138+
tips_lamports: prev.tips_lamports + tip,
123139
});
124140
}
125141
return chartData;
126142
},
127-
[{ timestampNanos: 0, computeUnits: 0, activeBankCount: 0 }],
143+
[
144+
{
145+
timestampNanos: 0,
146+
computeUnits: 0,
147+
activeBankCount: 0,
148+
priority_fees_lamports: 0,
149+
tips_lamports: 0,
150+
},
151+
],
128152
);
129153
}
130154

@@ -136,9 +160,10 @@ const getXTicks = memoize(function getXTicks(
136160
return prettyIntervals(tsMinNanos, tsMaxNanos, intervalCount);
137161
});
138162

139-
function getDataDomain(
163+
function getDataRangebyZoomWindow(
140164
data: ChartData[],
141-
maxComputeUnits: number,
165+
field: keyof ChartData,
166+
maxRangeValue: number,
142167
zoomRange: ZoomRange | undefined,
143168
): Domain | undefined {
144169
if (!data.length) return;
@@ -161,8 +186,8 @@ function getDataDomain(
161186
// if (pt.timestampNanos > endTime) break;
162187

163188
if (pt !== undefined) {
164-
min = Math.min(min, pt.computeUnits);
165-
max = Math.max(max, pt.computeUnits);
189+
min = Math.min(min, pt[field]);
190+
max = Math.max(max, pt[field]);
166191
}
167192

168193
// Doing the check after the min/max means we included an additional data point past
@@ -173,7 +198,22 @@ function getDataDomain(
173198
if (!Number.isFinite(min) || !Number.isFinite(max)) return;
174199

175200
const domain = extendDomain([min, max], 100);
176-
return [Math.max(0, domain[0]), Math.min(maxComputeUnits, domain[1])];
201+
return [Math.max(0, domain[0]), Math.min(maxRangeValue, domain[1])];
202+
}
203+
204+
function getDefaultYAxisTicks(
205+
numTicks: number,
206+
maxRangeValue: number,
207+
approxBottomPadding: number,
208+
interval: number,
209+
): Array<number> {
210+
const step =
211+
Math.ceil(
212+
(maxRangeValue - approxBottomPadding) / (numTicks - 1) / interval,
213+
) * interval;
214+
return Array.from({ length: numTicks }, (_, i) =>
215+
Math.min(maxRangeValue - i * step, maxRangeValue),
216+
);
177217
}
178218

179219
function getCuByTs({
@@ -375,9 +415,31 @@ export default function Chart({
375415
[xDomain, xLabelCount],
376416
);
377417

418+
const defaultCuTicks = useMemo(
419+
() => getDefaultYAxisTicks(6, maxComputeUnits, 8_000_000, 1_000_000),
420+
[maxComputeUnits],
421+
);
422+
423+
const maxIncomeValue = Math.max(
424+
data.reduce((sum, d) => sum + d.tips_lamports, 0),
425+
data.reduce((sum, d) => sum + d.priority_fees_lamports, 0),
426+
12_000_000,
427+
);
428+
const defaultIncomeTicks = useMemo(
429+
() => getDefaultYAxisTicks(6, maxIncomeValue, 2_000_000, 1_000_000),
430+
[maxIncomeValue],
431+
);
432+
378433
const cuDomain = useMemo(
379434
() =>
380-
fitYToData ? getDataDomain(data, maxComputeUnits, zoomRange) : undefined,
435+
fitYToData
436+
? getDataRangebyZoomWindow(
437+
data,
438+
"computeUnits",
439+
maxComputeUnits,
440+
zoomRange,
441+
)
442+
: undefined,
381443
[maxComputeUnits, data, fitYToData, zoomRange],
382444
);
383445

@@ -766,7 +828,7 @@ export default function Chart({
766828
yAxisId={bankCountAxisId}
767829
type="stepAfter"
768830
dataKey="activeBankCount"
769-
stroke="#BA7B1D"
831+
stroke="rgba(117, 77, 18, 1)"
770832
strokeWidth={
771833
useActiveBanksLargeStroke
772834
? 0.9
@@ -919,12 +981,32 @@ export default function Chart({
919981
yAxisId={cuAxisId}
920982
type="stepAfter"
921983
dataKey="computeUnits"
922-
stroke="#1288F6"
984+
stroke="rgba(105, 105, 255, 1)"
923985
strokeWidth={1.3}
924986
dot={false}
925987
name="CUs"
926988
isAnimationActive={false}
927989
/>
990+
<Line
991+
yAxisId={incomeAxisId}
992+
type="stepAfter"
993+
dataKey="priority_fees_lamports"
994+
stroke="rgba(82, 227, 203, 1)"
995+
strokeWidth={1.3}
996+
dot={false}
997+
name="Income"
998+
isAnimationActive={false}
999+
/>
1000+
<Line
1001+
yAxisId={incomeAxisId}
1002+
type="stepAfter"
1003+
dataKey="tips_lamports"
1004+
stroke="rgba(84, 211, 94, 1)"
1005+
strokeWidth={1.3}
1006+
dot={false}
1007+
name="Income"
1008+
isAnimationActive={false}
1009+
/>
9281010
<XAxis
9291011
dataKey="timestampNanos"
9301012
scale="time"
@@ -945,7 +1027,7 @@ export default function Chart({
9451027
ticks={cuDomain ? undefined : defaultCuTicks}
9461028
allowDataOverflow={!!cuDomain}
9471029
minTickGap={0}
948-
orientation="right"
1030+
orientation="left"
9491031
tickFormatter={(tick) => {
9501032
if (typeof tick !== "number") return "";
9511033

@@ -961,6 +1043,20 @@ export default function Chart({
9611043
hide
9621044
name="active bank tiles"
9631045
/>
1046+
<YAxis
1047+
yAxisId={incomeAxisId}
1048+
scale="linear"
1049+
type="number"
1050+
domain={["auto", "dataMax + 250000"]}
1051+
ticks={defaultIncomeTicks}
1052+
orientation="right"
1053+
tickFormatter={(tick) => {
1054+
if (typeof tick !== "number") return "";
1055+
return (
1056+
(tick / 1_000_000_000).toFixed(3).padEnd(3, "0") + " ꜱᴏʟ"
1057+
);
1058+
}}
1059+
/>
9641060

9651061
{isActiveDragging && (
9661062
<ReferenceArea

src/features/Overview/SlotPerformance/ComputeUnitsCard/ChartTooltip.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { TooltipProps } from "recharts";
22
import styles from "./computeUnits.module.css";
33
import { Text } from "@radix-ui/themes";
44
import clsx from "clsx";
5+
import { getFmtStake } from "../../../../utils";
56

67
export default function ChartTooltip(props: TooltipProps<number, string>) {
78
if (!props.active) return;
@@ -26,6 +27,14 @@ export default function ChartTooltip(props: TooltipProps<number, string>) {
2627
<Text className={styles.elapsedTime}>
2728
{(Number(props.label) / 1_000_000).toString()} ms
2829
</Text>
30+
<Text className={clsx(styles.tips, styles.label)}>Tips</Text>
31+
<Text className={styles.tips}>
32+
{getFmtStake(BigInt(props.payload?.[3]?.value || 0))}
33+
</Text>
34+
<Text className={clsx(styles.prioFee, styles.label)}>Prio Fee</Text>
35+
<Text className={styles.prioFee}>
36+
{getFmtStake(BigInt(props.payload?.[2]?.value || 0))}
37+
</Text>
2938
</div>
3039
);
3140
}

src/features/Overview/SlotPerformance/ComputeUnitsCard/computeUnits.module.css

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,25 @@
1515
}
1616

1717
.active-banks {
18-
color: #ba7b1d;
18+
color: rgba(117, 77, 18, 1);
1919
}
2020

2121
.compute-units {
22-
color: #1d77cb;
22+
color: rgba(105, 105, 255, 1);
2323
}
2424

2525
.elapsed-time {
2626
color: #6a6a6e;
2727
}
2828

29+
.prio-fee {
30+
color: rgba(82, 227, 203, 1);
31+
}
32+
33+
.tips {
34+
color: rgba(84, 211, 94, 1);
35+
}
36+
2937
.label {
3038
font-weight: 600;
3139
text-align: left;
@@ -39,12 +47,12 @@
3947
max-height: 600px;
4048
position: relative;
4149
margin-left: -8px;
42-
margin-right: -16px;
50+
margin-right: -8px;
4351

4452
.legend {
4553
position: absolute;
4654
top: 30px;
47-
left: 20px;
55+
left: 80px;
4856
display: flex;
4957
flex-direction: column;
5058
border-radius: 5px;

src/features/Overview/SlotPerformance/ComputeUnitsCard/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useAtomValue } from "jotai";
2-
import { useSlotQueryResponse } from "../../../../hooks/useSlotQuery";
2+
import { useSlotQueryResponseTransactions } from "../../../../hooks/useSlotQuery";
33
import { selectedSlotAtom, tileCountAtom } from "../atoms";
44
import Card from "../../../../components/Card";
55
import CardHeader from "../../../../components/CardHeader";
@@ -11,7 +11,7 @@ import Actions from "./Actions";
1111

1212
export default function ComputeUnitsCard() {
1313
const slot = useAtomValue(selectedSlotAtom);
14-
const query = useSlotQueryResponse(slot);
14+
const query = useSlotQueryResponseTransactions(slot);
1515

1616
const tileCount = useAtomValue(tileCountAtom);
1717
const bankTileCount = tileCount["bank"];
@@ -22,7 +22,7 @@ export default function ComputeUnitsCard() {
2222
<Card style={{ marginTop: "8px" }}>
2323
<Flex direction="column" height="100%" gap="2">
2424
<Flex gap="3">
25-
<CardHeader text="CU Progression" />
25+
<CardHeader text="Slot Progression" />
2626
<Actions />
2727
</Flex>
2828
<div className={styles.chart}>

src/features/Overview/SlotPerformance/SankeyControls.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Text, Tooltip } from "@radix-ui/themes";
33
import * as ToggleGroup from "@radix-ui/react-toggle-group";
44
import { useAtom, useAtomValue } from "jotai";
55
import { DisplayType, sankeyDisplayTypeAtom, selectedSlotAtom } from "./atoms";
6-
import { useSlotQueryResponse } from "../../../hooks/useSlotQuery";
6+
import { useSlotQueryResponseDetailed } from "../../../hooks/useSlotQuery";
77
import { fixValue } from "../../../utils";
88
import { useMemo } from "react";
99
import { lamportsPerSol } from "../../../consts";
@@ -52,7 +52,7 @@ export default function SankeyControls() {
5252

5353
function SlotStats() {
5454
const selectedSlot = useAtomValue(selectedSlotAtom);
55-
const query = useSlotQueryResponse(selectedSlot);
55+
const query = useSlotQueryResponseDetailed(selectedSlot);
5656

5757
const values = useMemo(() => {
5858
if (!query.response?.publish) return;

src/features/Overview/SlotPerformance/SlotSankey/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { TxnWaterfall, TxnWaterfallOut } from "../../../../api/types";
1212
import { Flex, Spinner, Text } from "@radix-ui/themes";
1313
import { SlotNode, slotNodes } from "./consts";
1414
import { sum } from "lodash";
15-
import { useSlotQueryResponse } from "../../../../hooks/useSlotQuery";
15+
import { useSlotQueryResponseDetailed } from "../../../../hooks/useSlotQuery";
1616

1717
function getGetValue({
1818
displayType,
@@ -342,7 +342,7 @@ function SlotSankey({ slot }: { slot?: number }) {
342342
const displayType = useAtomValue(sankeyDisplayTypeAtom);
343343
const liveWaterfall = useAtomValue(liveWaterfallAtom);
344344

345-
const query = useSlotQueryResponse(slot);
345+
const query = useSlotQueryResponseDetailed(slot);
346346

347347
const data = useMemo(() => {
348348
const waterfall = liveWaterfall ?? query.response?.waterfall;

src/features/Overview/SlotPerformance/TilePrimaryStat.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Text } from "@radix-ui/themes";
55
import { TilePrimaryMetric } from "../../../api/types";
66
import { selectedSlotAtom } from "./atoms";
77
import byteSize from "byte-size";
8-
import { useSlotQueryResponse } from "../../../hooks/useSlotQuery";
8+
import { useSlotQueryResponseDetailed } from "../../../hooks/useSlotQuery";
99

1010
interface TilePrimaryStatProps {
1111
type: keyof TilePrimaryMetric;
@@ -16,7 +16,7 @@ export default function TilePrimaryStat({ type, label }: TilePrimaryStatProps) {
1616
const slot = useAtomValue(selectedSlotAtom);
1717
const showLive = !slot;
1818
const primaryMetric = useAtomValue(liveTilePrimaryMetricAtom);
19-
const query = useSlotQueryResponse(showLive ? undefined : slot);
19+
const query = useSlotQueryResponseDetailed(showLive ? undefined : slot);
2020

2121
const stat = showLive
2222
? primaryMetric?.tile_primary_metric?.[type]

0 commit comments

Comments
 (0)