Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions src/app/bundles/[hash]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<Card>
Expand All @@ -330,7 +331,7 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) {
<div>
<div className="text-xs text-gray-500 mb-1">State Root</div>
<div className="text-xl font-semibold text-gray-900">
{meter.stateRootTimeUs.toLocaleString()}μs
{stateRootTimeUs.toLocaleString()}μs
</div>
</div>
<div>
Expand All @@ -340,23 +341,29 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) {
</div>
</div>
</div>
{(meter.stateRootAccountNodeCount > 0 ||
meter.stateRootStorageNodeCount > 0) && (
{((meter.stateRootAccountLeafCount ?? 0) > 0 ||
(meter.stateRootStorageLeafCount ?? 0) > 0) && (
<div className="grid grid-cols-2 gap-6 mt-4 pt-4 border-t border-gray-100">
<div>
<div className="text-xs text-gray-500 mb-1">
Account Trie Nodes
</div>
<div className="text-xl font-semibold text-gray-900">
{meter.stateRootAccountNodeCount.toLocaleString()}
{(
(meter.stateRootAccountLeafCount ?? 0) +
(meter.stateRootAccountBranchCount ?? 0)
).toLocaleString()}
</div>
</div>
<div>
<div className="text-xs text-gray-500 mb-1">
Storage Trie Nodes
</div>
<div className="text-xl font-semibold text-gray-900">
{meter.stateRootStorageNodeCount.toLocaleString()}
{(
(meter.stateRootStorageLeafCount ?? 0) +
(meter.stateRootStorageBranchCount ?? 0)
).toLocaleString()}
</div>
</div>
</div>
Expand All @@ -366,7 +373,7 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) {
<div>
<span className="text-gray-500">Total Gas</span>
<span className="ml-2 font-medium text-gray-900">
{meter.totalGasUsed.toLocaleString()}
{(meter.totalGasUsed ?? 0).toLocaleString()}
</span>
</div>
<div>
Expand Down
50 changes: 33 additions & 17 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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 (
<Card>
Expand All @@ -199,7 +204,7 @@ function MeteringCard({ meter }: { meter: MeterBundleResponse }) {
<div>
<div className="text-xs text-gray-500 mb-1">State Root</div>
<div className="text-xl font-semibold text-gray-900">
{meter.stateRootTimeUs.toLocaleString()}μs
{stateRootTimeUs.toLocaleString()}μs
</div>
</div>
<div>
Expand All @@ -209,23 +214,29 @@ function MeteringCard({ meter }: { meter: MeterBundleResponse }) {
</div>
</div>
</div>
{(meter.stateRootAccountNodeCount > 0 ||
meter.stateRootStorageNodeCount > 0) && (
{((meter.stateRootAccountLeafCount ?? 0) > 0 ||
(meter.stateRootStorageLeafCount ?? 0) > 0) && (
<div className="grid grid-cols-2 gap-6 mt-4 pt-4 border-t border-gray-100">
<div>
<div className="text-xs text-gray-500 mb-1">
Account Trie Nodes
</div>
<div className="text-xl font-semibold text-gray-900">
{meter.stateRootAccountNodeCount.toLocaleString()}
{(
(meter.stateRootAccountLeafCount ?? 0) +
(meter.stateRootAccountBranchCount ?? 0)
).toLocaleString()}
</div>
</div>
<div>
<div className="text-xs text-gray-500 mb-1">
Storage Trie Nodes
</div>
<div className="text-xl font-semibold text-gray-900">
{meter.stateRootStorageNodeCount.toLocaleString()}
{(
(meter.stateRootStorageLeafCount ?? 0) +
(meter.stateRootStorageBranchCount ?? 0)
).toLocaleString()}
</div>
</div>
</div>
Expand All @@ -235,7 +246,7 @@ function MeteringCard({ meter }: { meter: MeterBundleResponse }) {
<div>
<span className="text-gray-500">Total Gas</span>
<span className="ml-2 font-medium text-gray-900">
{meter.totalGasUsed.toLocaleString()}
{(meter.totalGasUsed ?? 0).toLocaleString()}
</span>
</div>
<div>
Expand Down Expand Up @@ -319,7 +330,8 @@ function RejectedTxRow({
<span className="text-xs text-gray-400">{timeAgo}</span>
</div>
<div className="text-xs text-gray-500 mt-0.5 truncate">
Block #{tx.blockNumber.toLocaleString()} — {tx.reason}
Block #{tx.blockNumber.toLocaleString()} —{" "}
{formatRejectionReason(tx.reason)}
</div>
</div>
<svg
Expand Down Expand Up @@ -357,7 +369,9 @@ function RejectedTxRow({
</tr>
<tr className="border-b border-gray-200/60">
<td className="text-gray-500 py-2">Reason</td>
<td className="py-2 text-red-700 font-medium">{tx.reason}</td>
<td className="py-2 text-red-700 font-medium">
{formatRejectionReason(tx.reason)}
</td>
</tr>
<tr>
<td className="text-gray-500 py-2">Rejected At</td>
Expand Down Expand Up @@ -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<Tab>(getInitialTab);
const [activeTab, setActiveTab] = useState<Tab>("blocks");

// Read hash on client only after hydration
useEffect(() => {
const hash = window.location.hash.replace("#", "");
if (hash === "rejected") {
setActiveTab("rejected");
}
}, []);
const [error, setError] = useState<string | null>(null);
const [blocks, setBlocks] = useState<BlockSummary[]>([]);
const [loading, setLoading] = useState(true);
Expand Down
26 changes: 23 additions & 3 deletions src/lib/s3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down
Loading