diff --git a/src/app/bundles/[hash]/page.tsx b/src/app/bundles/[hash]/page.tsx index 289ecbd..9ea8602 100644 --- a/src/app/bundles/[hash]/page.tsx +++ b/src/app/bundles/[hash]/page.tsx @@ -315,7 +315,8 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) { (sum, r) => sum + r.executionTimeUs, 0, ); - const totalTimeUs = executionTimeUs + meter.stateRootTimeUs; + const stateRootTimeUs = meter.stateRootTimeUs ?? 0; + const totalTimeUs = executionTimeUs + stateRootTimeUs; return ( @@ -330,7 +331,7 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) {
State Root
- {meter.stateRootTimeUs.toLocaleString()}μs + {stateRootTimeUs.toLocaleString()}μs
@@ -340,15 +341,18 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) {
- {(meter.stateRootAccountNodeCount > 0 || - meter.stateRootStorageNodeCount > 0) && ( + {((meter.stateRootAccountLeafCount ?? 0) > 0 || + (meter.stateRootStorageLeafCount ?? 0) > 0) && (
Account Trie Nodes
- {meter.stateRootAccountNodeCount.toLocaleString()} + {( + (meter.stateRootAccountLeafCount ?? 0) + + (meter.stateRootAccountBranchCount ?? 0) + ).toLocaleString()}
@@ -356,7 +360,10 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) { Storage Trie Nodes
- {meter.stateRootStorageNodeCount.toLocaleString()} + {( + (meter.stateRootStorageLeafCount ?? 0) + + (meter.stateRootStorageBranchCount ?? 0) + ).toLocaleString()}
@@ -366,7 +373,7 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) {
Total Gas - {meter.totalGasUsed.toLocaleString()} + {(meter.totalGasUsed ?? 0).toLocaleString()}
diff --git a/src/app/page.tsx b/src/app/page.tsx index 603a5e5..1b03119 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -3,7 +3,11 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; import { useCallback, useEffect, useState } from "react"; -import type { MeterBundleResponse, RejectedTransaction } from "@/lib/s3"; +import { + formatRejectionReason, + type MeterBundleResponse, + type RejectedTransaction, +} from "@/lib/s3"; import type { BlockSummary, BlocksResponse } from "./api/blocks/route"; import type { RejectedTransactionsResponse } from "./api/rejected/route"; @@ -184,7 +188,8 @@ function MeteringCard({ meter }: { meter: MeterBundleResponse }) { (sum, r) => sum + r.executionTimeUs, 0, ); - const totalTimeUs = executionTimeUs + meter.stateRootTimeUs; + const stateRootTimeUs = meter.stateRootTimeUs ?? 0; + const totalTimeUs = executionTimeUs + stateRootTimeUs; return ( @@ -199,7 +204,7 @@ function MeteringCard({ meter }: { meter: MeterBundleResponse }) {
State Root
- {meter.stateRootTimeUs.toLocaleString()}μs + {stateRootTimeUs.toLocaleString()}μs
@@ -209,15 +214,18 @@ function MeteringCard({ meter }: { meter: MeterBundleResponse }) {
- {(meter.stateRootAccountNodeCount > 0 || - meter.stateRootStorageNodeCount > 0) && ( + {((meter.stateRootAccountLeafCount ?? 0) > 0 || + (meter.stateRootStorageLeafCount ?? 0) > 0) && (
Account Trie Nodes
- {meter.stateRootAccountNodeCount.toLocaleString()} + {( + (meter.stateRootAccountLeafCount ?? 0) + + (meter.stateRootAccountBranchCount ?? 0) + ).toLocaleString()}
@@ -225,7 +233,10 @@ function MeteringCard({ meter }: { meter: MeterBundleResponse }) { Storage Trie Nodes
- {meter.stateRootStorageNodeCount.toLocaleString()} + {( + (meter.stateRootStorageLeafCount ?? 0) + + (meter.stateRootStorageBranchCount ?? 0) + ).toLocaleString()}
@@ -235,7 +246,7 @@ function MeteringCard({ meter }: { meter: MeterBundleResponse }) {
Total Gas - {meter.totalGasUsed.toLocaleString()} + {(meter.totalGasUsed ?? 0).toLocaleString()}
@@ -319,7 +330,8 @@ function RejectedTxRow({ {timeAgo}
- Block #{tx.blockNumber.toLocaleString()} — {tx.reason} + Block #{tx.blockNumber.toLocaleString()} —{" "} + {formatRejectionReason(tx.reason)}
Reason - {tx.reason} + + {formatRejectionReason(tx.reason)} +
Rejected At @@ -606,14 +620,16 @@ function RejectedTransactionsTab() { ); } -function getInitialTab(): Tab { - if (typeof window === "undefined") return "blocks"; - const hash = window.location.hash.replace("#", ""); - return hash === "rejected" ? "rejected" : "blocks"; -} - export default function Home() { - const [activeTab, setActiveTab] = useState(getInitialTab); + const [activeTab, setActiveTab] = useState("blocks"); + + // Read hash on client only after hydration + useEffect(() => { + const hash = window.location.hash.replace("#", ""); + if (hash === "rejected") { + setActiveTab("rejected"); + } + }, []); const [error, setError] = useState(null); const [blocks, setBlocks] = useState([]); const [loading, setLoading] = useState(true); diff --git a/src/lib/s3.ts b/src/lib/s3.ts index 47eb1c4..6e11aa1 100644 --- a/src/lib/s3.ts +++ b/src/lib/s3.ts @@ -129,8 +129,10 @@ export interface MeterBundleResponse { totalGasUsed: number; totalExecutionTimeUs: number; stateRootTimeUs: number; - stateRootAccountNodeCount: number; - stateRootStorageNodeCount: number; + stateRootAccountLeafCount: number; + stateRootAccountBranchCount: number; + stateRootStorageLeafCount: number; + stateRootStorageBranchCount: number; } export interface BundleData { @@ -247,14 +249,32 @@ export async function getBlockFromCache( } } +export interface RejectionReason { + executionTimeExceeded?: { + tx_time_us: number; + limit_us: number; + }; +} + export interface RejectedTransaction { blockNumber: number; txHash: string; - reason: string; + reason: RejectionReason; timestamp: number; metering: MeterBundleResponse; } +export function formatRejectionReason( + reason: RejectionReason | string, +): string { + if (typeof reason === "string") return reason; + if (reason?.executionTimeExceeded) { + const { tx_time_us, limit_us } = reason.executionTimeExceeded; + return `Execution time exceeded: ${tx_time_us.toLocaleString()}μs > ${limit_us.toLocaleString()}μs limit`; + } + return "Unknown reason"; +} + export interface RejectedTransactionSummary { blockNumber: number; txHash: string;