Skip to content

Commit 78468dd

Browse files
PabloCastellanoluis-herasmexFJAPJColombo
authored
feat: decode Optimism blobs (#529)
* feat: add optimism-decoder package * feat: Add error handling for undefined bytes in utils.ts * feat: added download.ts script + refactor * feat: Added saveFilesToDB * chore: Update npm scripts for saveFilesToDB * chore: update pnpm-lock.yaml * chore: Update pnpm-lock.yaml and package.json dependencies * chore: Add decoded transaction fields to transaction page * Update packages/optimism-decoder/src/decoder.ts Co-authored-by: Francisco Jiménez Aguilera <[email protected]> * add TODO issue links * refactor: move commands to its own package * fix: blob-decoder package import * pnpm lock * fix migration * chore: update turbo * op:generate-import-csv * add summary * Refactor transaction page to display decoded transaction data * chore: Add links to etherscan in the optimism decoded blob data * chore: bump turbo * chore: update turbo commands to v2 * Revert "chore: update turbo commands to v2" This reverts commit b58c63f. * Revert "chore: bump turbo" This reverts commit 441efd2. * Revert "chore: update turbo" This reverts commit 9a6ea15. * test: check for `decodedFields` * chore: resolve lint warnings * chore: add changeset * test(db): fix tests --------- Co-authored-by: Luis Herasme <[email protected]> Co-authored-by: Francisco Jiménez Aguilera <[email protected]> Co-authored-by: PJColombo <[email protected]>
1 parent 5a4a662 commit 78468dd

30 files changed

+1264
-11
lines changed

Diff for: .changeset/hot-badgers-hammer.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@blobscan/api": minor
3+
"@blobscan/web": minor
4+
---
5+
6+
Displayed Optimism decoded blob data

Diff for: .changeset/smart-toys-agree.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@blobscan/db": minor
3+
---
4+
5+
Added `decodedFields` JSON field for storing decoded-blob-related data

Diff for: apps/docs/src/app/docs/codebase-overview/page.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ Here you can find all the shared packages used by the apps:
5454
| [`@blobscan/blob-storage-manager`](https://github.com/Blobscan/blobscan/tree/next/packages/blob-storage-manager) | Orchestrates the storage/retrieval of blobs in/from different storage providers. Currently it supports [Google Cloud Storage](https://cloud.google.com/storage), [Swarm](https://www.ethswarm.org), PostgreSQL database and filesystem. |
5555
| [`@blobscan/dayjs`](https://github.com/Blobscan/blobscan/tree/next/packages/dayjs) |  Extended [Day.js](https://day.js.org/) with plugins. |
5656
| [`@blobscan/db`](https://github.com/Blobscan/blobscan/tree/next/packages/db) | Prisma schema and a Prisma client with [extensions](https://www.prisma.io/docs/concepts/components/prisma-client/client-extensions) containing custom methods queries. |
57-
| [`@blobscan/logger`](https://github.com/Blobscan/blobscan/tree/next/packages/logger) |  Shared logger utilities. |
58-
| |
59-
|  [`@blobscan/open-telemetry`](https://github.com/Blobscan/blobscan/tree/next/packages/open-telemetry) | [Otel](https://opentelemetry.io/) configuration and sdk setup. |
60-
| [`@blobscan/test`](https://github.com/Blobscan/blobscan/tree/next/packages/test) |  Shared test utilities and fixtures. |
61-
|  [`@blobscan/zod`](https://github.com/Blobscan/blobscan/tree/next/packages/zod) |  Shared [Zod](https://zod.dev) schemas and utilities. |
62-
|  [`@blobscan/eth-format`](https://github.com/Blobscan/blobscan/tree/next/packages/eth-format) |  Provides utility functions for handling Ethereum value conversions and formatting. |
63-
|  [`@blobscan/rollups`](https://github.com/Blobscan/blobscan/tree/next/packages/rollups) |  A utility that provides a comprehensive list of all rollups and their associated addresses supported by Blobscan, along with functions to retrieve them easily. |
57+
| [`@blobscan/logger`](https://github.com/Blobscan/blobscan/tree/next/packages/logger) | Shared logger utilities. |
58+
| [`@blobscan/optimism-decoder`](https://github.com/Blobscan/blobscan/tree/next/packages/optimism-decoder) | Optimism blobs decoder. |
59+
| [`@blobscan/open-telemetry`](https://github.com/Blobscan/blobscan/tree/next/packages/open-telemetry) | [Otel](https://opentelemetry.io/) configuration and sdk setup. |
60+
| [`@blobscan/test`](https://github.com/Blobscan/blobscan/tree/next/packages/test) | Shared test utilities and fixtures. |
61+
| [`@blobscan/zod`](https://github.com/Blobscan/blobscan/tree/next/packages/zod) | Shared [Zod](https://zod.dev) schemas and utilities. |
62+
| [`@blobscan/eth-format`](https://github.com/Blobscan/blobscan/tree/next/packages/eth-format) | Provides utility functions for handling Ethereum value conversions and formatting. |
63+
| [`@blobscan/rollups`](https://github.com/Blobscan/blobscan/tree/next/packages/rollups) | A utility that provides a comprehensive list of all rollups and their associated addresses supported by Blobscan, along with functions to retrieve them easily. |
6464

6565
### Tooling
6666

Diff for: apps/web/src/pages/tx/[hash].tsx

+88
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import { useMemo } from "react";
22
import type { NextPage } from "next";
33
import { useRouter } from "next/router";
44

5+
import { parseDecodedData } from "~/utils/decoded-transaction";
56
import { RollupBadge } from "~/components/Badges/RollupBadge";
67
import { Card } from "~/components/Cards/Card";
78
import { BlobCard } from "~/components/Cards/SurfaceCards/BlobCard";
89
import { Copyable, CopyToClipboard } from "~/components/CopyToClipboard";
910
import { StandardEtherUnitDisplay } from "~/components/Displays/StandardEtherUnitDisplay";
11+
import { InfoGrid } from "~/components/InfoGrid";
1012
import { DetailsLayout } from "~/components/Layouts/DetailsLayout";
1113
import type { DetailsLayoutProps } from "~/components/Layouts/DetailsLayout";
1214
import { Link } from "~/components/Link";
@@ -227,6 +229,11 @@ const Tx: NextPage = () => {
227229
);
228230
}
229231

232+
const decodedData =
233+
rawTxData && rawTxData.decodedFields
234+
? parseDecodedData(rawTxData.decodedFields)
235+
: null;
236+
230237
return (
231238
<>
232239
<DetailsLayout
@@ -249,6 +256,87 @@ const Tx: NextPage = () => {
249256
fields={detailsFields}
250257
/>
251258

259+
{rawTxData && rawTxData.decodedFields && (
260+
<Card header="Decoded transaction fields">
261+
{decodedData && (
262+
<div>
263+
<InfoGrid
264+
fields={[
265+
{
266+
name: "Timestamp since L2 genesis",
267+
value: (
268+
<div className="whitespace-break-spaces">
269+
{formatTimestamp(decodedData.timestampSinceL2Genesis)}
270+
</div>
271+
),
272+
},
273+
{
274+
name: "Last L1 origin number",
275+
value: decodedData.lastL1OriginNumber,
276+
},
277+
{
278+
name: "Parent L2 block hash",
279+
value: (
280+
<div className="flex items-center gap-2">
281+
<Link
282+
href={
283+
"https://etherscan.io/block/" +
284+
"0x" +
285+
decodedData.parentL2BlockHash
286+
}
287+
>
288+
{"0x" + decodedData.parentL2BlockHash}
289+
</Link>
290+
<CopyToClipboard
291+
value={"0x" + decodedData.parentL2BlockHash}
292+
label="Copy parent L2 block hash"
293+
/>
294+
</div>
295+
),
296+
},
297+
{
298+
name: "L1 origin block hash",
299+
value: (
300+
<div className="flex items-center gap-2">
301+
<Link
302+
href={
303+
"https://etherscan.io/block/" +
304+
"0x" +
305+
decodedData.l1OriginBlockHash
306+
}
307+
>
308+
{"0x" + decodedData.l1OriginBlockHash}
309+
</Link>
310+
<CopyToClipboard
311+
value={"0x" + decodedData.l1OriginBlockHash}
312+
label="Copy L1 origin block hash"
313+
/>
314+
</div>
315+
),
316+
},
317+
{
318+
name: "Number of L2 blocks",
319+
value: decodedData.numberOfL2Blocks,
320+
},
321+
{
322+
name: "Changed by L1 origin",
323+
value: decodedData.changedByL1Origin,
324+
},
325+
{
326+
name: "Total transactions",
327+
value: decodedData.totalTxs,
328+
},
329+
{
330+
name: "Contract creation transactions",
331+
value: decodedData.contractCreationTxsNumber,
332+
},
333+
]}
334+
/>
335+
</div>
336+
)}
337+
</Card>
338+
)}
339+
252340
<Card header={`Blobs ${tx ? `(${tx.blobs.length})` : ""}`}>
253341
<div className="space-y-6">
254342
{isLoading || !tx || !tx.blobs

Diff for: apps/web/src/utils/decoded-transaction.tsx

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { z } from "zod";
2+
3+
export const OptimismDecodedDataSchema = z.object({
4+
timestampSinceL2Genesis: z.number(),
5+
lastL1OriginNumber: z.number(),
6+
parentL2BlockHash: z.string(),
7+
l1OriginBlockHash: z.string(),
8+
numberOfL2Blocks: z.number(),
9+
changedByL1Origin: z.number(),
10+
totalTxs: z.number(),
11+
contractCreationTxsNumber: z.number(),
12+
});
13+
14+
type OptimismDecodedData = z.infer<typeof OptimismDecodedDataSchema>;
15+
16+
export function parseDecodedData(data: string): OptimismDecodedData | null {
17+
let json;
18+
19+
try {
20+
json = JSON.parse(data);
21+
} catch (error) {
22+
return null;
23+
}
24+
25+
const decoded = OptimismDecodedDataSchema.safeParse(json);
26+
27+
if (!decoded.success) {
28+
return null;
29+
}
30+
31+
return decoded.data;
32+
}

Diff for: docker-compose.local.yml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ services:
3030
- 5432:5432
3131
volumes:
3232
- postgres-data:/var/lib/postgresql/data
33+
- /tmp:/tmp
3334
environment:
3435
- POSTGRES_USER=blobscan
3536
- POSTGRES_DB=blobscan_dev

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"msw": "^2.3.1",
5656
"prettier": "^2.8.8",
5757
"prettier-plugin-tailwindcss": "^0.2.8",
58-
"ts-node": "^10.9.1",
58+
"ts-node": "^10.9.2",
5959
"ts-node-dev": "^2.0.0",
6060
"turbo": "^1.10.7",
6161
"typescript": "^5.2.2",
@@ -65,4 +65,4 @@
6565
"manypkg": {
6666
"workspaceProtocool": "require"
6767
}
68-
}
68+
}

Diff for: packages/api/src/routers/indexer/indexData.utils.ts

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export function createDBTransactions({
114114
blobAsCalldataGasUsed: bigIntToDecimal(blobGasAsCalldataUsed),
115115
rollup,
116116
category,
117+
decodedFields: null,
117118
};
118119
}
119120
);

Diff for: packages/api/src/routers/tx/common/selects.ts

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const baseTransactionSelect =
3434
blockNumber: true,
3535
blockTimestamp: true,
3636
index: true,
37+
decodedFields: true,
3738
});
3839

3940
export function createTransactionSelect(expands: Expands) {

Diff for: packages/api/src/routers/tx/common/serializers.ts

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const baseSerializedTransactionFieldsSchema = z.object({
4242
.merge(serializedExpandedBlobDataSchema)
4343
),
4444
block: serializedExpandedBlockSchema.optional(),
45+
decodedFields: z.string().optional(),
4546
});
4647

4748
export const serializedTransactionSchema =
@@ -129,5 +130,6 @@ export function serializeTransaction(
129130
return {
130131
...serializedBaseTx,
131132
...serializedAdditionalTx,
133+
decodedFields: JSON.stringify(txQuery.decodedFields),
132134
};
133135
}

0 commit comments

Comments
 (0)