ponder 0.9.2 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/bin/ponder.js +1933 -1606
  2. package/dist/bin/ponder.js.map +1 -1
  3. package/dist/{chunk-IFTUFVCL.js → chunk-LHCA5XFV.js} +2 -5
  4. package/dist/chunk-LHCA5XFV.js.map +1 -0
  5. package/dist/index.d.ts +5 -2
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/bin/commands/codegen.ts +8 -10
  10. package/src/bin/commands/dev.ts +30 -42
  11. package/src/bin/commands/list.ts +9 -14
  12. package/src/bin/commands/serve.ts +26 -39
  13. package/src/bin/commands/start.ts +29 -42
  14. package/src/bin/utils/{shutdown.ts → exit.ts} +23 -37
  15. package/src/bin/utils/run.ts +275 -175
  16. package/src/bin/utils/runServer.ts +1 -5
  17. package/src/build/index.ts +3 -8
  18. package/src/build/pre.ts +3 -0
  19. package/src/config/index.ts +5 -2
  20. package/src/database/index.ts +72 -72
  21. package/src/drizzle/kit/index.ts +3 -3
  22. package/src/indexing/index.ts +0 -4
  23. package/src/indexing/service.ts +31 -93
  24. package/src/indexing-store/historical.ts +2 -4
  25. package/src/internal/common.ts +2 -0
  26. package/src/internal/errors.ts +9 -9
  27. package/src/internal/logger.ts +1 -1
  28. package/src/internal/metrics.ts +75 -103
  29. package/src/internal/shutdown.ts +25 -0
  30. package/src/internal/telemetry.ts +16 -18
  31. package/src/internal/types.ts +9 -1
  32. package/src/server/index.ts +3 -5
  33. package/src/sync/events.ts +4 -4
  34. package/src/sync/filter.ts +1 -0
  35. package/src/sync/index.ts +1046 -805
  36. package/src/sync-historical/index.ts +0 -37
  37. package/src/sync-realtime/index.ts +48 -48
  38. package/src/sync-store/encoding.ts +5 -5
  39. package/src/sync-store/index.ts +5 -23
  40. package/src/ui/index.ts +2 -11
  41. package/src/utils/checkpoint.ts +17 -3
  42. package/src/utils/chunk.ts +7 -0
  43. package/src/utils/generators.ts +66 -0
  44. package/src/utils/mutex.ts +34 -0
  45. package/src/utils/partition.ts +41 -0
  46. package/src/utils/requestQueue.ts +19 -10
  47. package/src/utils/zipper.ts +80 -0
  48. package/dist/chunk-IFTUFVCL.js.map +0 -1
@@ -72,7 +72,6 @@ export type Build = {
72
72
  startDev: (params: {
73
73
  onReload: (kind: "indexing" | "api") => void;
74
74
  }) => void;
75
- kill: () => Promise<void>;
76
75
  };
77
76
 
78
77
  export const createBuild = async ({
@@ -133,6 +132,8 @@ export const createBuild = async ({
133
132
  plugins: [viteTsconfigPathsPlugin(), vitePluginPonder(common.options)],
134
133
  });
135
134
 
135
+ common.shutdown.add(() => viteDevServer.close());
136
+
136
137
  // This is Vite boilerplate (initializes the Rollup container).
137
138
  await viteDevServer.pluginContainer.buildStart({});
138
139
 
@@ -373,6 +374,7 @@ export const createBuild = async ({
373
374
  status: "success",
374
375
  result: {
375
376
  databaseConfig: preBuild.databaseConfig,
377
+ ordering: preBuild.ordering,
376
378
  },
377
379
  } as const;
378
380
  },
@@ -585,13 +587,6 @@ export const createBuild = async ({
585
587
 
586
588
  viteDevServer.watcher.on("change", onFileChange);
587
589
  },
588
- async kill() {
589
- await viteDevServer?.close();
590
- common.logger.debug({
591
- service: "build",
592
- msg: "Killed build service",
593
- });
594
- },
595
590
  } satisfies Build;
596
591
 
597
592
  return build;
package/src/build/pre.ts CHANGED
@@ -18,6 +18,7 @@ export function buildPre({
18
18
  options: Pick<Options, "rootDir" | "ponderDir">;
19
19
  }): {
20
20
  databaseConfig: DatabaseConfig;
21
+ ordering: NonNullable<Config["ordering"]>;
21
22
  logs: { level: "warn" | "info" | "debug"; msg: string }[];
22
23
  } {
23
24
  const logs: { level: "warn" | "info" | "debug"; msg: string }[] = [];
@@ -112,6 +113,7 @@ export function buildPre({
112
113
  return {
113
114
  databaseConfig,
114
115
  logs,
116
+ ordering: config.ordering ?? "omnichain",
115
117
  };
116
118
  }
117
119
 
@@ -131,6 +133,7 @@ export function safeBuildPre({
131
133
  return {
132
134
  status: "success",
133
135
  databaseConfig: result.databaseConfig,
136
+ ordering: result.ordering,
134
137
  logs: result.logs,
135
138
  } as const;
136
139
  } catch (_error) {
@@ -5,20 +5,22 @@ import type { AddressConfig } from "./address.js";
5
5
  import type { GetEventFilter } from "./eventFilter.js";
6
6
 
7
7
  export type Config = {
8
+ database?: DatabaseConfig;
9
+ ordering?: "omnichain" | "multichain";
8
10
  networks: { [networkName: string]: NetworkConfig<unknown> };
9
11
  contracts: { [contractName: string]: GetContract };
10
12
  accounts: { [accountName: string]: AccountConfig<unknown> };
11
- database?: DatabaseConfig;
12
13
  blocks: {
13
14
  [sourceName: string]: GetBlockFilter<unknown>;
14
15
  };
15
16
  };
16
17
 
17
18
  export type CreateConfigReturnType<networks, contracts, accounts, blocks> = {
19
+ database?: DatabaseConfig;
20
+ ordering?: "omnichain" | "multichain";
18
21
  networks: networks;
19
22
  contracts: contracts;
20
23
  accounts: accounts;
21
- database?: DatabaseConfig;
22
24
  blocks: blocks;
23
25
  };
24
26
 
@@ -29,6 +31,7 @@ export const createConfig = <
29
31
  const blocks = {},
30
32
  >(config: {
31
33
  database?: DatabaseConfig;
34
+ ordering?: "omnichain" | "multichain";
32
35
  // TODO: add jsdoc to these properties.
33
36
  networks: NetworksConfig<Narrow<networks>>;
34
37
  contracts?: ContractsConfig<networks, Narrow<contracts>>;
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { getPrimaryKeyColumns, getTableNames } from "@/drizzle/index.js";
3
3
  import { getColumnCasing } from "@/drizzle/kit/index.js";
4
4
  import type { Common } from "@/internal/common.js";
5
- import { IgnorableError, NonRetryableError } from "@/internal/errors.js";
5
+ import { NonRetryableError, ShutdownError } from "@/internal/errors.js";
6
6
  import type {
7
7
  IndexingBuild,
8
8
  NamespaceBuild,
@@ -17,10 +17,9 @@ import {
17
17
  } from "@/sync-store/migrations.js";
18
18
  import type { Drizzle } from "@/types/db.js";
19
19
  import {
20
+ MAX_CHECKPOINT_STRING,
21
+ ZERO_CHECKPOINT_STRING,
20
22
  decodeCheckpoint,
21
- encodeCheckpoint,
22
- maxCheckpoint,
23
- zeroCheckpoint,
24
23
  } from "@/utils/checkpoint.js";
25
24
  import { formatEta } from "@/utils/format.js";
26
25
  import { createPool, createReadonlyPool } from "@/utils/pg.js";
@@ -62,8 +61,6 @@ export type Database = {
62
61
  revert(args: { checkpoint: string }): Promise<void>;
63
62
  finalize(args: { checkpoint: string }): Promise<void>;
64
63
  complete(args: { checkpoint: string }): Promise<void>;
65
- unlock(): Promise<void>;
66
- kill(): Promise<void>;
67
64
  };
68
65
 
69
66
  export type PonderApp = {
@@ -91,8 +88,8 @@ export type PonderInternalSchema = {
91
88
  } & {
92
89
  [_: ReturnType<typeof getTableNames>[number]["reorg"]]: unknown & {
93
90
  operation_id: number;
94
- checkpoint: string;
95
91
  operation: 0 | 1 | 2;
92
+ checkpoint: string;
96
93
  };
97
94
  };
98
95
 
@@ -127,11 +124,10 @@ export const createDatabase = async ({
127
124
  }: {
128
125
  common: Common;
129
126
  namespace: NamespaceBuild;
130
- preBuild: PreBuild;
127
+ preBuild: Pick<PreBuild, "databaseConfig">;
131
128
  schemaBuild: Omit<SchemaBuild, "graphqlSchema">;
132
129
  }): Promise<Database> => {
133
130
  let heartbeatInterval: NodeJS.Timeout | undefined;
134
- let isKilled = false;
135
131
 
136
132
  ////////
137
133
  // Create schema, drivers, roles, and query builders
@@ -155,6 +151,22 @@ export const createDatabase = async ({
155
151
  : preBuild.databaseConfig.instance,
156
152
  };
157
153
 
154
+ common.shutdown.add(async () => {
155
+ clearInterval(heartbeatInterval);
156
+
157
+ await qb.internal
158
+ .updateTable("_ponder_meta")
159
+ .where("key", "=", "app")
160
+ .set({
161
+ value: sql`jsonb_set(value, '{is_locked}', to_jsonb(0))`,
162
+ })
163
+ .execute();
164
+
165
+ if (dialect === "pglite") {
166
+ await (driver as PGliteDriver).instance.close();
167
+ }
168
+ });
169
+
158
170
  const kyselyDialect = createPgliteKyselyDialect(driver.instance);
159
171
 
160
172
  await driver.instance.query(`CREATE SCHEMA IF NOT EXISTS "${namespace}"`);
@@ -251,6 +263,27 @@ export const createDatabase = async ({
251
263
  listen: undefined,
252
264
  } as PostgresDriver;
253
265
 
266
+ common.shutdown.add(async () => {
267
+ clearInterval(heartbeatInterval);
268
+
269
+ await qb.internal
270
+ .updateTable("_ponder_meta")
271
+ .where("key", "=", "app")
272
+ .set({
273
+ value: sql`jsonb_set(value, '{is_locked}', to_jsonb(0))`,
274
+ })
275
+ .execute();
276
+
277
+ const d = driver as PostgresDriver;
278
+ d.listen?.release();
279
+ await Promise.all([
280
+ d.internal.end(),
281
+ d.user.end(),
282
+ d.readonly.end(),
283
+ d.sync.end(),
284
+ ]);
285
+ });
286
+
254
287
  await driver.internal.query(`CREATE SCHEMA IF NOT EXISTS "${namespace}"`);
255
288
 
256
289
  qb = {
@@ -340,20 +373,15 @@ export const createDatabase = async ({
340
373
  // Helpers
341
374
  ////////
342
375
 
343
- /**
344
- * Undo operations in user tables by using the "reorg" tables.
345
- *
346
- * Note: "reorg" tables may contain operations that have not been applied to the
347
- * underlying tables, but only be 1 operation at most.
348
- */
376
+ /** Undo operations in user tables by using the "reorg" tables. */
349
377
  const revert = async ({
378
+ tx,
350
379
  tableName,
351
380
  checkpoint,
352
- tx,
353
381
  }: {
382
+ tx: Transaction<PonderInternalSchema>;
354
383
  tableName: ReturnType<typeof getTableNames>[number];
355
384
  checkpoint: string;
356
- tx: Transaction<PonderInternalSchema>;
357
385
  }) => {
358
386
  const primaryKeyColumns = getPrimaryKeyColumns(
359
387
  schemaBuild.schema[tableName.js] as PgTable,
@@ -432,7 +460,8 @@ export const createDatabase = async ({
432
460
  });
433
461
  };
434
462
 
435
- let checkpoint: string | undefined;
463
+ /** 'true' if `migrate` created new tables. */
464
+ let createdTables: boolean;
436
465
 
437
466
  const database = {
438
467
  driver,
@@ -458,15 +487,27 @@ export const createDatabase = async ({
458
487
  }
459
488
 
460
489
  try {
490
+ if (common.shutdown.isKilled) {
491
+ throw new ShutdownError();
492
+ }
493
+
461
494
  const result = await fn();
462
495
  common.metrics.ponder_database_method_duration.observe(
463
496
  { method: options.method },
464
497
  endClock(),
465
498
  );
499
+
500
+ if (common.shutdown.isKilled) {
501
+ throw new ShutdownError();
502
+ }
466
503
  return result;
467
504
  } catch (_error) {
468
505
  const error = _error as Error;
469
506
 
507
+ if (common.shutdown.isKilled) {
508
+ throw new ShutdownError();
509
+ }
510
+
470
511
  common.metrics.ponder_database_method_duration.observe(
471
512
  { method: options.method },
472
513
  endClock(),
@@ -475,14 +516,6 @@ export const createDatabase = async ({
475
516
  method: options.method,
476
517
  });
477
518
 
478
- if (isKilled) {
479
- common.logger.trace({
480
- service: "database",
481
- msg: `Ignored error during '${options.method}' database method, service is killed (id=${id})`,
482
- });
483
- throw new IgnorableError();
484
- }
485
-
486
519
  if (!hasError) {
487
520
  hasError = true;
488
521
  firstError = error;
@@ -839,7 +872,7 @@ export const createDatabase = async ({
839
872
  .executeTakeFirst()
840
873
  .then((row) => row?.value);
841
874
 
842
- let createdTables = false;
875
+ createdTables = false;
843
876
 
844
877
  if (previousApp === undefined) {
845
878
  await createEnums();
@@ -850,7 +883,7 @@ export const createDatabase = async ({
850
883
  (process.env.PONDER_EXPERIMENTAL_DB === "platform" &&
851
884
  previousApp.build_id !== buildId) ||
852
885
  (process.env.PONDER_EXPERIMENTAL_DB === "platform" &&
853
- previousApp.checkpoint === encodeCheckpoint(zeroCheckpoint))
886
+ previousApp.checkpoint === ZERO_CHECKPOINT_STRING)
854
887
  ) {
855
888
  for (const tableName of getTableNames(schemaBuild.schema)) {
856
889
  await tx.schema
@@ -887,14 +920,12 @@ export const createDatabase = async ({
887
920
 
888
921
  // write metadata
889
922
 
890
- checkpoint = encodeCheckpoint(zeroCheckpoint);
891
-
892
923
  const newApp = {
893
924
  is_locked: 1,
894
925
  is_dev: common.options.command === "dev" ? 1 : 0,
895
926
  heartbeat_at: Date.now(),
896
927
  build_id: buildId,
897
- checkpoint: encodeCheckpoint(zeroCheckpoint),
928
+ checkpoint: ZERO_CHECKPOINT_STRING,
898
929
  table_names: getTableNames(schemaBuild.schema).map(
899
930
  ({ sql }) => sql,
900
931
  ),
@@ -1012,9 +1043,8 @@ export const createDatabase = async ({
1012
1043
  }, common.options.databaseHeartbeatInterval);
1013
1044
  },
1014
1045
  async recoverCheckpoint() {
1015
- if (checkpoint !== undefined) {
1016
- return checkpoint;
1017
- }
1046
+ // new tables are empty
1047
+ if (createdTables) return ZERO_CHECKPOINT_STRING;
1018
1048
 
1019
1049
  return this.wrap(
1020
1050
  { method: "recoverCheckpoint", includeTraceLogs: true },
@@ -1027,7 +1057,7 @@ export const createDatabase = async ({
1027
1057
  .executeTakeFirstOrThrow()
1028
1058
  .then((row) => row.value);
1029
1059
 
1030
- if (app.checkpoint === encodeCheckpoint(zeroCheckpoint)) {
1060
+ if (app.checkpoint === ZERO_CHECKPOINT_STRING) {
1031
1061
  for (const tableName of getTableNames(schemaBuild.schema)) {
1032
1062
  await sql
1033
1063
  .raw(
@@ -1108,13 +1138,13 @@ RETURNS TRIGGER AS $$
1108
1138
  BEGIN
1109
1139
  IF TG_OP = 'INSERT' THEN
1110
1140
  INSERT INTO "${namespace}"."${tableName.reorg}" (${columnNames.join(",")}, operation, checkpoint)
1111
- VALUES (${columnNames.map((name) => `NEW.${name}`).join(",")}, 0, '${encodeCheckpoint(maxCheckpoint)}');
1141
+ VALUES (${columnNames.map((name) => `NEW.${name}`).join(",")}, 0, '${MAX_CHECKPOINT_STRING}');
1112
1142
  ELSIF TG_OP = 'UPDATE' THEN
1113
1143
  INSERT INTO "${namespace}"."${tableName.reorg}" (${columnNames.join(",")}, operation, checkpoint)
1114
- VALUES (${columnNames.map((name) => `OLD.${name}`).join(",")}, 1, '${encodeCheckpoint(maxCheckpoint)}');
1144
+ VALUES (${columnNames.map((name) => `OLD.${name}`).join(",")}, 1, '${MAX_CHECKPOINT_STRING}');
1115
1145
  ELSIF TG_OP = 'DELETE' THEN
1116
1146
  INSERT INTO "${namespace}"."${tableName.reorg}" (${columnNames.join(",")}, operation, checkpoint)
1117
- VALUES (${columnNames.map((name) => `OLD.${name}`).join(",")}, 2, '${encodeCheckpoint(maxCheckpoint)}');
1147
+ VALUES (${columnNames.map((name) => `OLD.${name}`).join(",")}, 2, '${MAX_CHECKPOINT_STRING}');
1118
1148
  END IF;
1119
1149
  RETURN NULL;
1120
1150
  END;
@@ -1151,13 +1181,9 @@ $$ LANGUAGE plpgsql
1151
1181
  await this.wrap({ method: "revert", includeTraceLogs: true }, () =>
1152
1182
  Promise.all(
1153
1183
  getTableNames(schemaBuild.schema).map((tableName) =>
1154
- qb.internal.transaction().execute((tx) =>
1155
- revert({
1156
- tableName,
1157
- checkpoint,
1158
- tx,
1159
- }),
1160
- ),
1184
+ qb.internal
1185
+ .transaction()
1186
+ .execute((tx) => revert({ tx, tableName, checkpoint })),
1161
1187
  ),
1162
1188
  ),
1163
1189
  );
@@ -1201,7 +1227,7 @@ $$ LANGUAGE plpgsql
1201
1227
  await qb.internal
1202
1228
  .updateTable(tableName.reorg)
1203
1229
  .set({ checkpoint })
1204
- .where("checkpoint", "=", encodeCheckpoint(maxCheckpoint))
1230
+ .where("checkpoint", "=", MAX_CHECKPOINT_STRING)
1205
1231
  .execute();
1206
1232
  },
1207
1233
  ),
@@ -1224,32 +1250,6 @@ $$ LANGUAGE plpgsql
1224
1250
  },
1225
1251
  );
1226
1252
  },
1227
- async kill() {
1228
- isKilled = true;
1229
-
1230
- if (dialect === "pglite") {
1231
- const d = driver as PGliteDriver;
1232
- await d.instance.close();
1233
- }
1234
-
1235
- if (dialect === "pglite_test") {
1236
- // no-op, allow test harness to clean up the instance
1237
- }
1238
-
1239
- if (dialect === "postgres") {
1240
- const d = driver as PostgresDriver;
1241
- d.listen?.release();
1242
- await d.internal.end();
1243
- await d.user.end();
1244
- await d.readonly.end();
1245
- await d.sync.end();
1246
- }
1247
-
1248
- common.logger.debug({
1249
- service: "database",
1250
- msg: "Closed connection to database",
1251
- });
1252
- },
1253
1253
  } satisfies Database;
1254
1254
 
1255
1255
  // @ts-ignore
@@ -109,9 +109,9 @@ const createReorgTableStatement = (statement: JsonCreateTableStatement) => {
109
109
  generatePgSnapshot(
110
110
  [
111
111
  pgTable("", {
112
- operation_id: serial("operation_id").notNull().primaryKey(),
113
- operation: integer("operation").notNull(),
114
- checkpoint: varchar("checkpoint", {
112
+ operation_id: serial().notNull().primaryKey(),
113
+ operation: integer().notNull(),
114
+ checkpoint: varchar({
115
115
  length: 75,
116
116
  }).notNull(),
117
117
  }),
@@ -1,20 +1,16 @@
1
1
  import { type Extend, extend } from "@/utils/extend.js";
2
2
  import {
3
3
  create,
4
- kill,
5
4
  processEvents,
6
5
  processSetupEvents,
7
6
  setIndexingStore,
8
- updateTotalSeconds,
9
7
  } from "./service.js";
10
8
  import type { Context, Service } from "./service.js";
11
9
 
12
10
  const methods = {
13
11
  create,
14
- kill,
15
12
  processEvents,
16
13
  processSetupEvents,
17
- updateTotalSeconds,
18
14
  setIndexingStore,
19
15
  };
20
16
 
@@ -1,5 +1,6 @@
1
1
  import type { IndexingStore } from "@/indexing-store/index.js";
2
2
  import type { Common } from "@/internal/common.js";
3
+ import { ShutdownError } from "@/internal/errors.js";
3
4
  import type {
4
5
  ContractSource,
5
6
  Event,
@@ -10,23 +11,25 @@ import type {
10
11
  SetupEvent,
11
12
  Source,
12
13
  } from "@/internal/types.js";
14
+ import type { SyncStore } from "@/sync-store/index.js";
13
15
  import { isAddressFactory } from "@/sync/filter.js";
14
- import type { Sync } from "@/sync/index.js";
16
+ import { cachedTransport } from "@/sync/transport.js";
15
17
  import type { Db } from "@/types/db.js";
16
18
  import type { Block, Log, Trace, Transaction } from "@/types/eth.js";
17
19
  import type { DeepPartial } from "@/types/utils.js";
18
20
  import {
19
- type Checkpoint,
21
+ ZERO_CHECKPOINT,
20
22
  decodeCheckpoint,
21
23
  encodeCheckpoint,
22
- zeroCheckpoint,
23
24
  } from "@/utils/checkpoint.js";
24
25
  import { prettyPrint } from "@/utils/print.js";
26
+ import type { RequestQueue } from "@/utils/requestQueue.js";
25
27
  import { startClock } from "@/utils/timer.js";
26
- import type { Abi, Address } from "viem";
27
- import { checksumAddress, createClient } from "viem";
28
+ import { type Abi, type Address, createClient } from "viem";
29
+ import { checksumAddress } from "viem";
28
30
  import { addStackTrace } from "./addStackTrace.js";
29
- import { type ReadOnlyClient, getPonderActions } from "./ponderActions.js";
31
+ import type { ReadOnlyClient } from "./ponderActions.js";
32
+ import { getPonderActions } from "./ponderActions.js";
30
33
 
31
34
  export type Context = {
32
35
  network: { chainId: number; name: string };
@@ -49,12 +52,9 @@ export type Service = {
49
52
  indexingFunctions: IndexingFunctions;
50
53
 
51
54
  // state
52
- isKilled: boolean;
53
-
54
55
  eventCount: {
55
56
  [eventName: string]: number;
56
57
  };
57
- startCheckpoint: Checkpoint;
58
58
 
59
59
  /**
60
60
  * Reduce memory usage by reserving space for objects ahead of time
@@ -76,14 +76,16 @@ export type Service = {
76
76
  export const create = ({
77
77
  common,
78
78
  indexingBuild: { sources, networks, indexingFunctions },
79
- sync,
79
+ requestQueues,
80
+ syncStore,
80
81
  }: {
81
82
  common: Common;
82
83
  indexingBuild: Pick<
83
84
  IndexingBuild,
84
85
  "sources" | "networks" | "indexingFunctions"
85
86
  >;
86
- sync: Sync;
87
+ requestQueues: RequestQueue[];
88
+ syncStore: SyncStore;
87
89
  }): Service => {
88
90
  const contextState: Service["currentEvent"]["contextState"] = {
89
91
  blockNumber: undefined!,
@@ -139,10 +141,12 @@ export const create = ({
139
141
  }
140
142
 
141
143
  // build clientByChainId
142
- for (const network of networks) {
143
- const transport = sync.getCachedTransport(network);
144
+ for (let i = 0; i < networks.length; i++) {
145
+ const network = networks[i]!;
146
+ const requestQueue = requestQueues[i]!;
147
+
144
148
  clientByChainId[network.chainId] = createClient({
145
- transport,
149
+ transport: cachedTransport({ requestQueue, syncStore }),
146
150
  chain: network.chain,
147
151
  // @ts-ignore
148
152
  }).extend(getPonderActions(contextState));
@@ -157,9 +161,7 @@ export const create = ({
157
161
  return {
158
162
  common,
159
163
  indexingFunctions,
160
- isKilled: false,
161
164
  eventCount,
162
- startCheckpoint: decodeCheckpoint(sync.getStartCheckpoint()),
163
165
  currentEvent: {
164
166
  contextState,
165
167
  context: {
@@ -184,11 +186,7 @@ export const processSetupEvents = async (
184
186
  sources: Source[];
185
187
  networks: Network[];
186
188
  },
187
- ): Promise<
188
- | { status: "error"; error: Error }
189
- | { status: "success" }
190
- | { status: "killed" }
191
- > => {
189
+ ): Promise<{ status: "error"; error: Error } | { status: "success" }> => {
192
190
  for (const eventName of Object.keys(indexingService.indexingFunctions)) {
193
191
  if (!eventName.endsWith(":setup")) continue;
194
192
 
@@ -204,8 +202,6 @@ export const processSetupEvents = async (
204
202
 
205
203
  if (source === undefined) continue;
206
204
 
207
- if (indexingService.isKilled) return { status: "killed" };
208
-
209
205
  indexingService.eventCount[eventName]!++;
210
206
 
211
207
  const result = await executeSetup(indexingService, {
@@ -213,7 +209,7 @@ export const processSetupEvents = async (
213
209
  type: "setup",
214
210
  chainId: network.chainId,
215
211
  checkpoint: encodeCheckpoint({
216
- ...zeroCheckpoint,
212
+ ...ZERO_CHECKPOINT,
217
213
  chainId: BigInt(network.chainId),
218
214
  blockNumber: BigInt(source.filter.fromBlock ?? 0),
219
215
  }),
@@ -236,14 +232,8 @@ export const processSetupEvents = async (
236
232
  export const processEvents = async (
237
233
  indexingService: Service,
238
234
  { events }: { events: Event[] },
239
- ): Promise<
240
- | { status: "error"; error: Error }
241
- | { status: "success" }
242
- | { status: "killed" }
243
- > => {
235
+ ): Promise<{ status: "error"; error: Error } | { status: "success" }> => {
244
236
  for (let i = 0; i < events.length; i++) {
245
- if (indexingService.isKilled) return { status: "killed" };
246
-
247
237
  const event = events[i]!;
248
238
 
249
239
  indexingService.eventCount[event.name]!++;
@@ -262,40 +252,8 @@ export const processEvents = async (
262
252
  service: "indexing",
263
253
  msg: `Completed indexing function (event="${event.name}", checkpoint=${event.checkpoint})`,
264
254
  });
265
-
266
- // periodically update metrics
267
- if (i % 93 === 0) {
268
- updateCompletedEvents(indexingService);
269
-
270
- const eventTimestamp = decodeCheckpoint(event.checkpoint).blockTimestamp;
271
-
272
- indexingService.common.metrics.ponder_indexing_completed_seconds.set(
273
- eventTimestamp - indexingService.startCheckpoint.blockTimestamp,
274
- );
275
- indexingService.common.metrics.ponder_indexing_completed_timestamp.set(
276
- eventTimestamp,
277
- );
278
-
279
- // Note: allows for terminal and logs to be updated
280
- await new Promise(setImmediate);
281
- }
282
255
  }
283
256
 
284
- // set completed seconds
285
- if (events.length > 0) {
286
- const lastEventInBatchTimestamp = decodeCheckpoint(
287
- events[events.length - 1]!.checkpoint,
288
- ).blockTimestamp;
289
-
290
- indexingService.common.metrics.ponder_indexing_completed_seconds.set(
291
- lastEventInBatchTimestamp -
292
- indexingService.startCheckpoint.blockTimestamp,
293
- );
294
- indexingService.common.metrics.ponder_indexing_completed_timestamp.set(
295
- lastEventInBatchTimestamp,
296
- );
297
- }
298
- // set completed events
299
257
  updateCompletedEvents(indexingService);
300
258
 
301
259
  return { status: "success" };
@@ -314,24 +272,6 @@ export const setIndexingStore = (
314
272
  };
315
273
  };
316
274
 
317
- export const kill = (indexingService: Service) => {
318
- indexingService.common.logger.debug({
319
- service: "indexing",
320
- msg: "Killed indexing service",
321
- });
322
- indexingService.isKilled = true;
323
- };
324
-
325
- export const updateTotalSeconds = (
326
- indexingService: Service,
327
- endCheckpoint: Checkpoint,
328
- ) => {
329
- indexingService.common.metrics.ponder_indexing_total_seconds.set(
330
- endCheckpoint.blockTimestamp -
331
- indexingService.startCheckpoint.blockTimestamp,
332
- );
333
- };
334
-
335
275
  const updateCompletedEvents = (indexingService: Service) => {
336
276
  for (const event of Object.keys(indexingService.eventCount)) {
337
277
  const metricLabel = {
@@ -347,11 +287,7 @@ const updateCompletedEvents = (indexingService: Service) => {
347
287
  const executeSetup = async (
348
288
  indexingService: Service,
349
289
  { event }: { event: SetupEvent },
350
- ): Promise<
351
- | { status: "error"; error: Error }
352
- | { status: "success" }
353
- | { status: "killed" }
354
- > => {
290
+ ): Promise<{ status: "error"; error: Error } | { status: "success" }> => {
355
291
  const {
356
292
  common,
357
293
  indexingFunctions,
@@ -382,9 +318,12 @@ const executeSetup = async (
382
318
  endClock(),
383
319
  );
384
320
  } catch (_error) {
385
- if (indexingService.isKilled) return { status: "killed" };
386
321
  const error = _error instanceof Error ? _error : new Error(String(_error));
387
322
 
323
+ if (common.shutdown.isKilled) {
324
+ throw new ShutdownError();
325
+ }
326
+
388
327
  addStackTrace(error, common.options);
389
328
  addErrorMeta(error, toErrorMeta(event));
390
329
 
@@ -406,11 +345,7 @@ const executeSetup = async (
406
345
  const executeEvent = async (
407
346
  indexingService: Service,
408
347
  { event }: { event: Event },
409
- ): Promise<
410
- | { status: "error"; error: Error }
411
- | { status: "success" }
412
- | { status: "killed" }
413
- > => {
348
+ ): Promise<{ status: "error"; error: Error } | { status: "success" }> => {
414
349
  const {
415
350
  common,
416
351
  indexingFunctions,
@@ -442,9 +377,12 @@ const executeEvent = async (
442
377
  endClock(),
443
378
  );
444
379
  } catch (_error) {
445
- if (indexingService.isKilled) return { status: "killed" };
446
380
  const error = _error instanceof Error ? _error : new Error(String(_error));
447
381
 
382
+ if (common.shutdown.isKilled) {
383
+ throw new ShutdownError();
384
+ }
385
+
448
386
  addStackTrace(error, common.options);
449
387
  addErrorMeta(error, toErrorMeta(event));
450
388