diff --git a/src/api/atoms.ts b/src/api/atoms.ts index 0a4ff16..c12b10e 100644 --- a/src/api/atoms.ts +++ b/src/api/atoms.ts @@ -11,7 +11,7 @@ import { EstimatedTps, EstimatedSlotDuration, IdentityBalance, - UptimeNanos, + StartupTimeNanos, LiveTxnWaterfall, StartupProgress, LiveTilePrimaryMetric, @@ -23,7 +23,6 @@ import { BlockEngineUpdate, VoteBalance, } from "./types"; -import { DateTime } from "luxon"; import { rafAtom } from "../atomUtils"; export const versionAtom = atom(undefined); @@ -34,8 +33,8 @@ export const commitHashAtom = atom(undefined); export const identityKeyAtom = atom(undefined); -export const uptimeAtom = atom< - { uptimeNanos: UptimeNanos; ts: DateTime } | undefined +export const startupTimeAtom = atom< + { startupTimeNanos: StartupTimeNanos } | undefined >(undefined); export const tilesAtom = atom(undefined); diff --git a/src/api/entities.ts b/src/api/entities.ts index 550d37a..7d54469 100644 --- a/src/api/entities.ts +++ b/src/api/entities.ts @@ -44,7 +44,7 @@ export const commitHashSchema = z.string(); export const identityKeySchema = z.string(); -export const uptimeNanosSchema = z.coerce.bigint(); +export const startupTimeNanosSchema = z.coerce.bigint(); export const tileTypeSchema = z.enum([ "sock", @@ -247,9 +247,10 @@ export const slotPublishSchema = z.object({ mine: z.boolean(), skipped: z.boolean(), level: slotLevelSchema, - transactions: z.number().nullable(), - vote_transactions: z.number().nullable(), - failed_transactions: z.number().nullable(), + success_nonvote_transaction_cnt: z.number().nullable(), + failed_nonvote_transaction_cnt: z.number().nullable(), + success_vote_transaction_cnt: z.number().nullable(), + failed_vote_transaction_cnt: z.number().nullable(), priority_fee: z.coerce.bigint().nullable(), transaction_fee: z.coerce.bigint().nullable(), tips: z.coerce.bigint().nullable(), @@ -302,8 +303,8 @@ export const summarySchema = z.discriminatedUnion("key", [ value: identityKeySchema, }), summaryTopicSchema.extend({ - key: z.literal("uptime_nanos"), - value: uptimeNanosSchema, + key: z.literal("startup_time_nanos"), + value: startupTimeNanosSchema, }), summaryTopicSchema.extend({ key: z.literal("tiles"), diff --git a/src/api/types.ts b/src/api/types.ts index 97ae609..ecff95c 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -32,7 +32,7 @@ import { txnWaterfallInSchema, txnWaterfallOutSchema, txnWaterfallSchema, - uptimeNanosSchema, + startupTimeNanosSchema, versionSchema, voteDistanceSchema, voteStateSchema, @@ -48,7 +48,7 @@ export type CommitHash = z.infer; export type IdentityKey = z.infer; -export type UptimeNanos = z.infer; +export type StartupTimeNanos = z.infer; export type Tile = z.infer; diff --git a/src/api/useSetAtomWsData.ts b/src/api/useSetAtomWsData.ts index c9e64b4..29e9252 100644 --- a/src/api/useSetAtomWsData.ts +++ b/src/api/useSetAtomWsData.ts @@ -14,7 +14,7 @@ import { tilesAtom, tileTimerAtom, tpsHistoryAtom, - uptimeAtom, + startupTimeAtom, versionAtom, voteDistanceAtom, voteStateAtom, @@ -58,8 +58,7 @@ import { waterfallDebounceMs, } from "./consts"; import { rateLiveWaterfallAtom } from "../features/Overview/SlotPerformance/atoms"; - -const minuteNanos = 1_000_000 * 60 * 1_000; +import { slowDateTimeNow } from "../utils"; export function useSetAtomWsData() { const setVersion = useSetAtom(versionAtom); @@ -72,9 +71,18 @@ export function useSetAtomWsData() { const setIdentityBalance = useSetAtom(identityBalanceAtom); const setVoteBalance = useSetAtom(voteBalanceAtom); - const [uptime, setUptime] = useAtom(uptimeAtom); + const [startupTime, setStartupTime] = useAtom(startupTimeAtom); + + const uptimeDuration = + startupTime !== undefined + ? slowDateTimeNow.diff( + DateTime.fromMillis( + Math.floor(Number(startupTime.startupTimeNanos) / 1_000_000), + ), + ) + : undefined; const uptimeMins = - uptime !== undefined ? Number(uptime.uptimeNanos) / minuteNanos : undefined; + uptimeDuration !== undefined ? uptimeDuration.get("minutes") : undefined; const setEstimatedSlotDuration = useSetAtom(estimatedSlotDurationAtom); const setDbEstimatedSlotDuration = useThrottledCallback( @@ -180,8 +188,8 @@ export function useSetAtomWsData() { setVoteBalance(value); break; } - case "uptime_nanos": { - setUptime({ uptimeNanos: value, ts: DateTime.now() }); + case "startup_time_nanos": { + setStartupTime({ startupTimeNanos: value }); break; } case "tiles": { diff --git a/src/features/Header/IdentityKey.tsx b/src/features/Header/IdentityKey.tsx index 379b960..b73aa6f 100644 --- a/src/features/Header/IdentityKey.tsx +++ b/src/features/Header/IdentityKey.tsx @@ -1,7 +1,7 @@ import { useAtomValue } from "jotai"; import { identityBalanceAtom, - uptimeAtom, + startupTimeAtom, voteBalanceAtom, } from "../../api/atoms"; import { Text, Flex, Tooltip } from "@radix-ui/themes"; @@ -9,7 +9,7 @@ import styles from "./identityKey.module.css"; import PeerIcon from "../../components/PeerIcon"; import { myStakePctAtom, myStakeAmountAtom } from "../../atoms"; import { PropsWithChildren, useEffect } from "react"; -import { Duration } from "luxon"; +import { DateTime } from "luxon"; import { getFmtStake, getTimeTillText, slowDateTimeNow } from "../../utils"; import { formatNumber } from "../../numUtils"; import { useInterval, useMedia, useUpdate } from "react-use"; @@ -56,7 +56,7 @@ export default function IdentityKey() { )} {isNarrowScreen && ( <> - + @@ -98,7 +98,7 @@ function DropdownMenu() { - + @@ -206,18 +206,18 @@ function Commission() { ); } -function Uptime() { - const uptime = useAtomValue(uptimeAtom); +function StartupTime() { + const startupTime = useAtomValue(startupTimeAtom); const getValue = () => { - if (!uptime) return "-"; - - const uptimeDuration = Duration.fromMillis( - Number(uptime.uptimeNanos) / 1_000_000, + if (!startupTime) return "-"; + const uptimeDuration = slowDateTimeNow.diff( + DateTime.fromMillis( + Math.floor(Number(startupTime.startupTimeNanos) / 1_000_000), + ), ); - const diffDuration = slowDateTimeNow.diff(uptime.ts); - const text = getTimeTillText(uptimeDuration.plus(diffDuration).rescale(), { + const text = getTimeTillText(uptimeDuration.rescale(), { showSeconds: false, }); return text; diff --git a/src/features/LeaderSchedule/Slots/SlotCardGrid.tsx b/src/features/LeaderSchedule/Slots/SlotCardGrid.tsx index 1485ec5..7b19b83 100644 --- a/src/features/LeaderSchedule/Slots/SlotCardGrid.tsx +++ b/src/features/LeaderSchedule/Slots/SlotCardGrid.tsx @@ -204,10 +204,14 @@ interface SlotCardRowProps { } function getRowValues(publish: SlotPublish): RowValues { - // TODO: fix backend - const voteTxns = fixValue(publish.vote_transactions ?? 0); - const totalTxns = fixValue(publish.transactions ?? 0); - const nonVoteTxns = totalTxns - voteTxns; + const voteTxnsSuccess = fixValue(publish.success_vote_transaction_cnt ?? 0); + const nonVoteTxnsSuccess = fixValue( + publish.success_nonvote_transaction_cnt ?? 0, + ); + const voteTxnsFailure = fixValue(publish.failed_vote_transaction_cnt ?? 0); + const nonVoteTxnsFailure = fixValue( + publish.failed_nonvote_transaction_cnt ?? 0, + ); const totalFees = formatNumberLamports( (publish.transaction_fee ?? 0n) + (publish.priority_fee ?? 0n), 3, @@ -250,8 +254,8 @@ function getRowValues(publish: SlotPublish): RowValues { : 0; return { - voteTxns: voteTxns.toLocaleString(), - nonVoteTxns: nonVoteTxns.toLocaleString(), + voteTxns: (voteTxnsSuccess + voteTxnsFailure).toLocaleString(), + nonVoteTxns: (nonVoteTxnsSuccess + nonVoteTxnsFailure).toLocaleString(), totalFees, transactionFeeFull, priorityFeeFull, diff --git a/src/features/Overview/SlotPerformance/SankeyControls.tsx b/src/features/Overview/SlotPerformance/SankeyControls.tsx index 59a7f7d..ed02c66 100644 --- a/src/features/Overview/SlotPerformance/SankeyControls.tsx +++ b/src/features/Overview/SlotPerformance/SankeyControls.tsx @@ -58,9 +58,18 @@ function SlotStats() { const values = useMemo(() => { if (!query.response?.publish) return; - const voteTxns = fixValue(query.response.publish.vote_transactions ?? 0); - const totalTxns = fixValue(query.response.publish.transactions ?? 0); - const nonVoteTxns = totalTxns - voteTxns; + const successfulVoteTxns = fixValue( + query.response.publish.success_vote_transaction_cnt ?? 0, + ); + const successfulNonvoteTxns = fixValue( + query.response.publish.success_nonvote_transaction_cnt ?? 0, + ); + const failedVoteTxns = fixValue( + query.response.publish.failed_vote_transaction_cnt ?? 0, + ); + const failedNonvoteTxns = fixValue( + query.response.publish.failed_nonvote_transaction_cnt ?? 0, + ); const transactionFee3Decimals = query.response.publish.transaction_fee ? formatNumber( @@ -106,8 +115,10 @@ function SlotStats() { return { computeUnits, - voteTxns, - nonVoteTxns, + successfulVoteTxns, + successfulNonvoteTxns, + failedVoteTxns, + failedNonvoteTxns, transactionFeeFull, transactionFee3Decimals, priorityFeeFull, @@ -153,9 +164,19 @@ function SlotStats() { Vote Transactions - {values?.voteTxns?.toLocaleString() ?? "-"} + + {(values + ? values.failedVoteTxns + values.successfulVoteTxns + : undefined + )?.toLocaleString() ?? "-"} + Non-vote Transactions - {values?.nonVoteTxns?.toLocaleString() ?? "-"} + + {(values + ? values.failedNonvoteTxns + values.successfulNonvoteTxns + : undefined + )?.toLocaleString() ?? "-"} +
diff --git a/src/features/Overview/SlotPerformance/SlotSankey/index.tsx b/src/features/Overview/SlotPerformance/SlotSankey/index.tsx index 863906b..0d4d3e5 100644 --- a/src/features/Overview/SlotPerformance/SlotSankey/index.tsx +++ b/src/features/Overview/SlotPerformance/SlotSankey/index.tsx @@ -99,8 +99,8 @@ function getLinks( waterfall: TxnWaterfall, displayType: DisplayType, durationNanos?: number | null, - totalTransactions?: number | null, - failedTransactions?: number | null, + totalTransactions?: number, + failedTransactions?: number, ) { const totalIncoming = sum(Object.values(waterfall.in)); const getValue = getGetValue({ displayType, durationNanos, totalIncoming }); @@ -355,12 +355,25 @@ function SlotSankey({ slot }: { slot?: number }) { if (!waterfall) return; + const successfulTransactions = + query.response?.publish?.success_nonvote_transaction_cnt != null && + query.response.publish.success_vote_transaction_cnt != null + ? query.response.publish.success_nonvote_transaction_cnt + + query.response.publish.success_vote_transaction_cnt + : waterfall.out.block_success; + const failedTransactions = + query.response?.publish.failed_nonvote_transaction_cnt != null && + query.response.publish.failed_vote_transaction_cnt != null + ? query.response.publish.failed_nonvote_transaction_cnt + + query.response.publish.failed_vote_transaction_cnt + : waterfall.out.block_fail; + const links = getLinks( waterfall, displayType, query.response?.publish.duration_nanos, - query.response?.publish.transactions, - query.response?.publish.failed_transactions, + successfulTransactions + failedTransactions, + failedTransactions, ); const linkNodes = links.flatMap((l) => [l.source, l.target]);