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
31 changes: 21 additions & 10 deletions src/app/api/block/[hash]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@ async function buildAndCacheBlockData(
): Promise<BlockData> {
const transactions: BlockTransaction[] = await Promise.all(
rpcBlock.transactions.map(async (tx, index) => {
const { bundleId, executionTimeUs } =
const { bundleId, executionTimeUs, stateRootTimeUs } =
await enrichTransactionWithBundleData(tx.hash);
return {
hash: tx.hash,
from: tx.from,
to: tx.to,
gasUsed: tx.gas,
executionTimeUs,
stateRootTimeUs,
bundleId,
index,
};
Expand Down Expand Up @@ -109,34 +110,43 @@ function isSystemTransaction(tx: BlockTransaction): boolean {
return tx.index === 0;
}

async function enrichTransactionWithBundleData(
txHash: string,
): Promise<{ bundleId: string | null; executionTimeUs: number | null }> {
async function enrichTransactionWithBundleData(txHash: string): Promise<{
bundleId: string | null;
executionTimeUs: number | null;
stateRootTimeUs: number | null;
}> {
const metadata = await getTransactionMetadataByHash(txHash);
if (!metadata || metadata.bundle_ids.length === 0) {
return { bundleId: null, executionTimeUs: null };
return { bundleId: null, executionTimeUs: null, stateRootTimeUs: null };
}

const bundleId = metadata.bundle_ids[0];
const bundleHistory = await getBundleHistory(bundleId);
if (!bundleHistory) {
return { bundleId, executionTimeUs: null };
return { bundleId, executionTimeUs: null, stateRootTimeUs: null };
}

const receivedEvent = bundleHistory.history.find(
(e) => e.event === "Received",
);
if (!receivedEvent?.data?.bundle?.meter_bundle_response?.results) {
return { bundleId, executionTimeUs: null };
return { bundleId, executionTimeUs: null, stateRootTimeUs: null };
}

const txResult = receivedEvent.data.bundle.meter_bundle_response.results.find(
const meterResponse = receivedEvent.data.bundle.meter_bundle_response;

// TODO: Switch to meterResponse.totalExecutionTimeUs once 0.7 is deployed.
// On 0.6, totalExecutionTimeUs is the wall-clock total_time_us which includes
// setup, teardown, and state root (double-counting stateRootTimeUs). PR #1111
// fixes this on main to be the sum of per-tx execution times.
const txResult = meterResponse.results.find(
(r: MeterBundleResult) => r.txHash.toLowerCase() === txHash.toLowerCase(),
);

return {
bundleId,
executionTimeUs: txResult?.executionTimeUs ?? null,
stateRootTimeUs: meterResponse.stateRootTimeUs ?? null,
};
}

Expand All @@ -153,9 +163,9 @@ async function refetchMissingTransactionSimulations(

const refetchResults = await Promise.all(
transactionsToRefetch.map(async (tx) => {
const { bundleId, executionTimeUs } =
const { bundleId, executionTimeUs, stateRootTimeUs } =
await enrichTransactionWithBundleData(tx.hash);
return { hash: tx.hash, bundleId, executionTimeUs };
return { hash: tx.hash, bundleId, executionTimeUs, stateRootTimeUs };
}),
);

Expand All @@ -168,6 +178,7 @@ async function refetchMissingTransactionSimulations(
...tx,
bundleId: refetchResult.bundleId,
executionTimeUs: refetchResult.executionTimeUs,
stateRootTimeUs: refetchResult.stateRootTimeUs,
};
}
return tx;
Expand Down
30 changes: 22 additions & 8 deletions src/app/block/[hash]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,18 @@ function getHeatmapStyle(

function TransactionRow({
tx,
maxExecutionTime,
maxTotalTime,
}: {
tx: BlockTransaction;
maxExecutionTime: number;
maxTotalTime: number;
}) {
const hasBundle = tx.bundleId !== null;
const hasExecutionTime = tx.executionTimeUs !== null;
const executionTime = tx.executionTimeUs ?? 0;
const stateRootTime = tx.stateRootTimeUs ?? 0;
const totalTime = executionTime + stateRootTime;
const heatmapStyle = hasExecutionTime
? getHeatmapStyle(executionTime, maxExecutionTime)
? getHeatmapStyle(totalTime, maxTotalTime)
: null;

const content = (
Expand Down Expand Up @@ -144,7 +146,7 @@ function TransactionRow({
<span
className={`inline-block px-2 py-0.5 rounded text-sm font-medium ${heatmapStyle.bg} ${heatmapStyle.text}`}
>
{executionTime.toLocaleString()}μs
{totalTime.toLocaleString()}μs
</span>
) : (
<div className="text-sm font-medium text-gray-400">—</div>
Expand All @@ -171,14 +173,18 @@ function BlockStats({ block }: { block: BlockData }) {
(sum, tx) => sum + (tx.executionTimeUs ?? 0),
0,
);
const totalStateRootTime = txsWithTime.reduce(
(sum, tx) => sum + (tx.stateRootTimeUs ?? 0),
0,
);
const bundleCount = block.transactions.filter(
(tx) => tx.bundleId !== null,
).length;

return (
<Card>
<div className="p-5">
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6">
<div className="grid grid-cols-2 lg:grid-cols-5 gap-6">
<div>
<div className="text-xs text-gray-500 mb-1">Block Number</div>
<div className="text-xl font-semibold text-gray-900">
Expand All @@ -205,6 +211,14 @@ function BlockStats({ block }: { block: BlockData }) {
: "—"}
</div>
</div>
<div>
<div className="text-xs text-gray-500 mb-1">Total State Root</div>
<div className="text-xl font-semibold text-gray-900">
{totalStateRootTime > 0
? `${totalStateRootTime.toLocaleString()}μs`
: "—"}
</div>
</div>
</div>
</div>
<div className="border-t border-gray-100 px-5 py-3 bg-gray-50/50 grid grid-cols-3 gap-4 text-xs">
Expand Down Expand Up @@ -284,11 +298,11 @@ export default function BlockPage({ params }: PageProps) {
);
}

const maxExecutionTime = data
const maxTotalTime = data
? Math.max(
...data.transactions
.filter((tx) => tx.executionTimeUs !== null)
.map((tx) => tx.executionTimeUs ?? 0),
.map((tx) => (tx.executionTimeUs ?? 0) + (tx.stateRootTimeUs ?? 0)),
0,
)
: 0;
Expand Down Expand Up @@ -478,7 +492,7 @@ export default function BlockPage({ params }: PageProps) {
<TransactionRow
key={tx.hash}
tx={tx}
maxExecutionTime={maxExecutionTime}
maxTotalTime={maxTotalTime}
/>
))}
</div>
Expand Down
1 change: 1 addition & 0 deletions src/lib/s3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export interface BlockTransaction {
to: string | null;
gasUsed: bigint;
executionTimeUs: number | null;
stateRootTimeUs: number | null;
bundleId: string | null;
index: number;
}
Expand Down
Loading