Skip to content

Commit c280050

Browse files
authored
feat: getting latest tx-effects (#348)
* fixes and tests * ui getting there * less changes
1 parent 1d1537c commit c280050

File tree

18 files changed

+215
-115
lines changed

18 files changed

+215
-115
lines changed

k8s/local/ethereum-listener/skaffold.sp_testnet.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ deploy:
88
apply: ["--force"]
99
manifests:
1010
rawYaml:
11+
- ./sp_testnet/postgres-config.yaml
1112
- ./sp_testnet/deployment.yaml

k8s/local/ethereum-listener/sp_testnet/deployment.yaml

+19-2
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,37 @@ spec:
1616
labels:
1717
app: ethereum-listener-sp-testnet-label
1818
spec:
19+
initContainers:
20+
- name: run-migrations
21+
image: ethereum-listener:latest
22+
command: ["yarn", run, "migrate"]
23+
envFrom:
24+
- configMapRef:
25+
name: postgres-config-global
26+
- configMapRef:
27+
name: postgres-config-ethereum-listener-sp-testnet
28+
env:
29+
- name: TOTAL_DB_RESET
30+
value: "false"
1931
containers:
2032
- image: ethereum-listener:latest
2133
resources:
2234
limits:
2335
memory: 150Mi
2436
cpu: 500m
2537
name: ethereum-listener
38+
envFrom:
39+
- configMapRef:
40+
name: postgres-config-global
41+
- configMapRef:
42+
name: postgres-config-ethereum-listener-sp-testnet
2643
env:
2744
- name: INSTANCE_NAME
2845
value: "sp_testnet_ethereum-listener"
2946
- name: L2_NETWORK_ID
3047
value: "SP_TESTNET"
31-
- name: BLOCK_POLL_INTERVAL_MS
32-
value: "5000"
48+
- name: LISTENER_DISABLED
49+
value: "false"
3350
- name: GENESIS_CATCHUP
3451
value: "true"
3552
- name: LISTEN_FOR_BLOCKS
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: postgres-config-ethereum-listener-sp-testnet
5+
namespace: chicmoz
6+
data:
7+
POSTGRES_DB_NAME: "ethereum_listener_sp_testnet"

k8s/local/postgres/values.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ primary:
1212
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'aztec_listener_remote_devnet')\gexec
1313
select 'CREATE DATABASE ethereum_listener_sandbox'
1414
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'ethereum_listener_sandbox')\gexec
15+
select 'CREATE DATABASE ethereum_listener_sp_testnet'
16+
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'ethereum_listener_sp_testnet')\gexec
1517
SELECT 'CREATE DATABASE explorer_api_sandbox'
1618
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'explorer_api_sandbox')\gexec
1719
SELECT 'CREATE DATABASE explorer_api_sp_testnet'

k8s/local/skaffold.sp_testnet.yaml

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ metadata:
44
name: sp_testnet
55
requires:
66
- path: ./common/skaffold.infra.yaml
7-
- path: ./common/skaffold.aztec_sanbox_nodes.yaml
8-
- path: ./aztec-listener/skaffold.sp_testnet.yaml
97
- path: ./explorer-ui/skaffold.sp_testnet.yaml
108
- path: ./ethereum-listener/skaffold.sp_testnet.yaml
119
- path: ./explorer-api/skaffold.sp_testnet.yaml
1210
- path: ./auth/skaffold.yaml
1311
- path: ./websocket-event-publisher/skaffold.sp_testnet.yaml
12+
- path: ./aztec-listener/skaffold.sp_testnet.yaml

packages/types/src/aztec/l2Block.ts

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export enum ChicmozL2BlockFinalizationStatus {
2323
L1_MINED_PROVEN = 5,
2424
}
2525

26+
export const FIRST_FINALIZATION_STATUS =
27+
ChicmozL2BlockFinalizationStatus.L2_NODE_SEEN_PROPOSED;
28+
2629
export const LAST_FINALIZATION_STATUS =
2730
ChicmozL2BlockFinalizationStatus.L1_MINED_PROVEN;
2831

services/explorer-api/src/svcs/database/controllers/l2TxEffect/get-tx-effect.ts

+57-24
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
HexString,
66
chicmozL2TxEffectDeluxeSchema,
77
} from "@chicmoz-pkg/types";
8-
import { SQL, and, asc, eq, getTableColumns } from "drizzle-orm";
8+
import assert from "assert";
9+
import { SQL, and, asc, desc, eq, getTableColumns, gte, lt } from "drizzle-orm";
910
import { z } from "zod";
1011
import { DB_MAX_TX_EFFECTS } from "../../../../environment.js";
1112
import {
@@ -18,23 +19,24 @@ import {
1819
} from "../../../database/schema/l2block/index.js";
1920

2021
enum GetTypes {
21-
BlockHeight,
22+
BlockHeightRange,
2223
BlockHeightAndIndex,
2324
}
2425

2526
type GetTxEffectByBlockHeightAndIndex = {
2627
blockHeight: bigint;
27-
txEffectIndex: number
28+
txEffectIndex: number;
2829
getType: GetTypes.BlockHeightAndIndex;
2930
};
3031

31-
type GetTxEffectsByBlockHeight = {
32-
blockHeight: bigint;
33-
getType: GetTypes.BlockHeight;
32+
type GetTxEffectsByBlockHeightRange = {
33+
from?: bigint;
34+
to?: bigint;
35+
getType: GetTypes.BlockHeightRange;
3436
};
3537

3638
export const getTxEffectNestedByHash = async (
37-
txEffectHash: string
39+
txEffectHash: string,
3840
): Promise<Pick<ChicmozL2TxEffect, "publicDataWrites">> => {
3941
const publicDataWrites = await db()
4042
.select({
@@ -52,27 +54,52 @@ export const getTxEffectNestedByHash = async (
5254

5355
export const getTxEffectByBlockHeightAndIndex = async (
5456
blockHeight: bigint,
55-
txEffectIndex: number
57+
txEffectIndex: number,
5658
): Promise<ChicmozL2TxEffectDeluxe | null> => {
5759
const res = await _getTxEffects({
5860
blockHeight,
5961
txEffectIndex,
6062
getType: GetTypes.BlockHeightAndIndex,
6163
});
6264

63-
if (res.length === 0) return null;
65+
if (res.length === 0) {return null;}
6466

6567
return res[0];
6668
};
6769

6870
export const getTxEffectsByBlockHeight = async (
69-
height: bigint
71+
height: bigint,
7072
): Promise<ChicmozL2TxEffectDeluxe[]> => {
71-
return _getTxEffects({ blockHeight: height, getType: GetTypes.BlockHeight });
73+
return _getTxEffects({
74+
from: height,
75+
to: height,
76+
getType: GetTypes.BlockHeightRange,
77+
});
78+
};
79+
80+
export const getLatestTxEffects = async (): Promise<
81+
ChicmozL2TxEffectDeluxe[]
82+
> => {
83+
return _getTxEffects({
84+
getType: GetTypes.BlockHeightRange,
85+
});
86+
};
87+
88+
const generateWhereQuery = (from?: bigint, to?: bigint) => {
89+
if (from && !to) {
90+
return gte(l2Block.height, from);
91+
} else if (!from && to) {
92+
return lt(l2Block.height, to);
93+
}
94+
assert(
95+
from && to,
96+
"FATAL: cannot have both from and to undefined when generating where query",
97+
);
98+
return and(gte(l2Block.height, from), lt(l2Block.height, to));
7299
};
73100

74101
const _getTxEffects = async (
75-
args: GetTxEffectByBlockHeightAndIndex | GetTxEffectsByBlockHeight
102+
args: GetTxEffectByBlockHeightAndIndex | GetTxEffectsByBlockHeightRange,
76103
): Promise<ChicmozL2TxEffectDeluxe[]> => {
77104
const joinQuery = db()
78105
.select({
@@ -89,19 +116,25 @@ const _getTxEffects = async (
89116
let whereQuery;
90117

91118
switch (args.getType) {
92-
case GetTypes.BlockHeight:
93-
whereQuery = joinQuery
94-
.where(eq(l2Block.height, args.blockHeight))
95-
.orderBy(asc(txEffect.index))
96-
.limit(DB_MAX_TX_EFFECTS);
119+
case GetTypes.BlockHeightRange:
120+
if (args.from ?? args.to) {
121+
whereQuery = joinQuery
122+
.where(generateWhereQuery(args.from, args.to))
123+
.orderBy(desc(txEffect.index), desc(l2Block.height))
124+
.limit(DB_MAX_TX_EFFECTS);
125+
} else {
126+
whereQuery = joinQuery
127+
.orderBy(desc(txEffect.index), desc(l2Block.height))
128+
.limit(DB_MAX_TX_EFFECTS);
129+
}
97130
break;
98131
case GetTypes.BlockHeightAndIndex:
99132
whereQuery = joinQuery
100133
.where(
101134
and(
102135
eq(l2Block.height, args.blockHeight),
103-
eq(txEffect.index, args.txEffectIndex)
104-
)
136+
eq(txEffect.index, args.txEffectIndex),
137+
),
105138
)
106139
.limit(1);
107140
break;
@@ -117,26 +150,26 @@ const _getTxEffects = async (
117150
txBirthTimestamp: txEffect.txBirthTimestamp.valueOf(),
118151
...nestedData,
119152
};
120-
})
153+
}),
121154
);
122155

123156
return z.array(chicmozL2TxEffectDeluxeSchema).parse(txEffects);
124157
};
125158

126159
export const getTxEffectByTxHash = async (
127-
txHash: HexString
160+
txHash: HexString,
128161
): Promise<ChicmozL2TxEffectDeluxe | null> => {
129162
return getTxEffectDynamicWhere(eq(txEffect.txHash, txHash));
130163
};
131164

132165
export const getTxEffectByHash = async (
133-
hash: HexString
166+
hash: HexString,
134167
): Promise<ChicmozL2TxEffectDeluxe | null> => {
135168
return getTxEffectDynamicWhere(eq(txEffect.txHash, hash));
136169
};
137170

138171
export const getTxEffectDynamicWhere = async (
139-
whereMatcher: SQL<unknown>
172+
whereMatcher: SQL<unknown>,
140173
): Promise<ChicmozL2TxEffectDeluxe | null> => {
141174
const dbRes = await db()
142175
.select({
@@ -153,7 +186,7 @@ export const getTxEffectDynamicWhere = async (
153186
.limit(1)
154187
.execute();
155188

156-
if (dbRes.length === 0) return null;
189+
if (dbRes.length === 0) {return null;}
157190

158191
const nestedData = await getTxEffectNestedByHash(dbRes[0].txHash);
159192

services/explorer-api/src/svcs/database/controllers/l2block/get-block.ts

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { getDb as db } from "@chicmoz-pkg/postgres-helper";
22
import {
33
ChicmozL2BlockLight,
4+
FIRST_FINALIZATION_STATUS,
45
HexString,
56
chicmozL2BlockLightSchema,
67
} from "@chicmoz-pkg/types";
@@ -27,6 +28,7 @@ import {
2728
} from "../../../database/schema/l2block/index.js";
2829
import { l2BlockFinalizationStatusTable } from "../../schema/l2block/finalization-status.js";
2930
import { getBlocksWhereRange, getTableColumnsWithoutId } from "../utils.js";
31+
import {logger} from "../../../../logger.js";
3032

3133
enum GetTypes {
3234
BlockHeight,
@@ -61,27 +63,27 @@ export const getBlocks = async ({
6163
};
6264

6365
export const getBlock = async (
64-
heightOrHash: bigint | HexString
66+
heightOrHash: bigint | HexString,
6567
): Promise<ChicmozL2BlockLight | null> => {
6668
const res = await _getBlocks(
6769
typeof heightOrHash === "bigint"
6870
? { height: heightOrHash, getType: GetTypes.BlockHeight }
69-
: { hash: heightOrHash, getType: GetTypes.BlockHash }
71+
: { hash: heightOrHash, getType: GetTypes.BlockHash },
7072
);
71-
if (res.length === 0) return null;
73+
if (res.length === 0) {return null;}
7274
return res[0];
7375
};
7476

7577
type GetBlocksArgs = GetBlocksByHeight | GetBlocksByHash | GetBlocksByRange;
7678

7779
const _getBlocks = async (
78-
args: GetBlocksArgs
80+
args: GetBlocksArgs,
7981
): Promise<ChicmozL2BlockLight[]> => {
8082
const whereRange =
8183
args.getType === GetTypes.Range ? getBlocksWhereRange(args) : undefined;
8284

8385
if (args.getType === GetTypes.BlockHeight)
84-
if (args.height < -1) throw new Error("Invalid height");
86+
{if (args.height < -1) {throw new Error("Invalid height");}}
8587

8688
const joinQuery = db()
8789
.select({
@@ -122,12 +124,12 @@ const _getBlocks = async (
122124
l1L2BlockProposedTable,
123125
and(
124126
eq(l2Block.height, l1L2BlockProposedTable.l2BlockNumber),
125-
eq(archive.root, l1L2BlockProposedTable.archive)
126-
)
127+
eq(archive.root, l1L2BlockProposedTable.archive),
128+
),
127129
)
128130
.leftJoin(
129131
l1L2ProofVerifiedTable,
130-
eq(l2Block.height, l1L2ProofVerifiedTable.l2BlockNumber)
132+
eq(l2Block.height, l1L2ProofVerifiedTable.l2BlockNumber),
131133
);
132134

133135
let whereQuery;
@@ -168,14 +170,20 @@ const _getBlocks = async (
168170
.where(eq(l2BlockFinalizationStatusTable.l2BlockHash, result.hash))
169171
.orderBy(
170172
desc(l2BlockFinalizationStatusTable.status),
171-
desc(l2BlockFinalizationStatusTable.l2BlockNumber)
173+
desc(l2BlockFinalizationStatusTable.l2BlockNumber),
172174
)
173175
.limit(1);
174176

177+
let finalizationStatusValue = finalizationStatus[0]?.status;
178+
if (finalizationStatusValue === undefined) {
179+
finalizationStatusValue = FIRST_FINALIZATION_STATUS;
180+
logger.warn(`Finalization status not found for block ${result.hash}`);
181+
}
182+
175183
const blockData = {
176184
hash: result.hash,
177185
height: result.height,
178-
finalizationStatus: finalizationStatus[0].status,
186+
finalizationStatus: finalizationStatusValue,
179187
archive: result.archive,
180188
proposedOnL1: result.l1L2BlockProposed?.l1BlockTimestamp
181189
? result.l1L2BlockProposed

services/explorer-api/src/svcs/http-server/routes/controllers/tx-effects.ts

+17
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ import {
1111
txEffectResponseArray,
1212
} from "./utils/index.js";
1313

14+
export const openapi_GET_L2_TX_EFFECTS = {
15+
"/l2/txEffects": {
16+
get: {
17+
summary: "Get all transaction effects",
18+
responses: txEffectResponseArray,
19+
},
20+
},
21+
};
22+
23+
export const GET_L2_TX_EFFECTS = asyncHandler(async (_req, res) => {
24+
// TODO: this should be extended to enable querying for block-height ranges
25+
const txEffectsData = await dbWrapper.getLatest(["l2", "txEffects"], () =>
26+
db.l2TxEffect.getLatestTxEffects()
27+
);
28+
res.status(200).send(txEffectsData);
29+
});
30+
1431
export const openapi_GET_L2_TX_EFFECTS_BY_BLOCK_HEIGHT = {
1532
"/l2/blocks/{blockHeight}/txEffects": {
1633
get: {

0 commit comments

Comments
 (0)