ponder 0.17.12 → 0.18.0

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 (153) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/esm/bin/commands/codegen.js +3 -3
  3. package/dist/esm/bin/commands/codegen.js.map +1 -1
  4. package/dist/esm/bin/commands/dev.js +3 -3
  5. package/dist/esm/bin/commands/dev.js.map +1 -1
  6. package/dist/esm/bin/commands/serve.js +3 -3
  7. package/dist/esm/bin/commands/serve.js.map +1 -1
  8. package/dist/esm/bin/commands/start.js +3 -3
  9. package/dist/esm/bin/commands/start.js.map +1 -1
  10. package/dist/esm/build/config.js +19 -20
  11. package/dist/esm/build/config.js.map +1 -1
  12. package/dist/esm/build/index.js +79 -65
  13. package/dist/esm/build/index.js.map +1 -1
  14. package/dist/esm/build/plugin.js +9 -0
  15. package/dist/esm/build/plugin.js.map +1 -1
  16. package/dist/esm/build/stacktrace.js +25 -68
  17. package/dist/esm/build/stacktrace.js.map +1 -1
  18. package/dist/esm/database/index.js +83 -67
  19. package/dist/esm/database/index.js.map +1 -1
  20. package/dist/esm/index.js +1 -0
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/indexing/client.js +35 -23
  23. package/dist/esm/indexing/client.js.map +1 -1
  24. package/dist/esm/indexing/index.js +3 -1
  25. package/dist/esm/indexing/index.js.map +1 -1
  26. package/dist/esm/rpc/actions.js +143 -67
  27. package/dist/esm/rpc/actions.js.map +1 -1
  28. package/dist/esm/runtime/events.js +33 -19
  29. package/dist/esm/runtime/events.js.map +1 -1
  30. package/dist/esm/runtime/filter.js +10 -9
  31. package/dist/esm/runtime/filter.js.map +1 -1
  32. package/dist/esm/runtime/fragments.js +50 -24
  33. package/dist/esm/runtime/fragments.js.map +1 -1
  34. package/dist/esm/runtime/historical.js +212 -68
  35. package/dist/esm/runtime/historical.js.map +1 -1
  36. package/dist/esm/runtime/index.js +11 -15
  37. package/dist/esm/runtime/index.js.map +1 -1
  38. package/dist/esm/runtime/isolated.js +1 -0
  39. package/dist/esm/runtime/isolated.js.map +1 -1
  40. package/dist/esm/runtime/multichain.js +1 -0
  41. package/dist/esm/runtime/multichain.js.map +1 -1
  42. package/dist/esm/runtime/omnichain.js +1 -0
  43. package/dist/esm/runtime/omnichain.js.map +1 -1
  44. package/dist/esm/runtime/realtime.js +17 -16
  45. package/dist/esm/runtime/realtime.js.map +1 -1
  46. package/dist/esm/server/index.js +8 -6
  47. package/dist/esm/server/index.js.map +1 -1
  48. package/dist/esm/sync-historical/in-memory.js +539 -0
  49. package/dist/esm/sync-historical/in-memory.js.map +1 -0
  50. package/dist/esm/sync-historical/index.js +46 -63
  51. package/dist/esm/sync-historical/index.js.map +1 -1
  52. package/dist/esm/sync-realtime/index.js +56 -83
  53. package/dist/esm/sync-realtime/index.js.map +1 -1
  54. package/dist/esm/sync-store/encode.js +1 -6
  55. package/dist/esm/sync-store/encode.js.map +1 -1
  56. package/dist/esm/sync-store/index.js +58 -62
  57. package/dist/esm/sync-store/index.js.map +1 -1
  58. package/dist/esm/sync-store/schema.js +23 -15
  59. package/dist/esm/sync-store/schema.js.map +1 -1
  60. package/dist/esm/sync-store/sql/ponder_rpc_cache_1/copy.sql +23 -0
  61. package/dist/esm/sync-store/sql/ponder_rpc_cache_1/create.sql +130 -0
  62. package/dist/esm/utils/finality.js +41 -32
  63. package/dist/esm/utils/finality.js.map +1 -1
  64. package/dist/esm/utils/pglite.js +0 -65
  65. package/dist/esm/utils/pglite.js.map +1 -1
  66. package/dist/types/bin/commands/codegen.d.ts.map +1 -1
  67. package/dist/types/bin/commands/dev.d.ts.map +1 -1
  68. package/dist/types/bin/commands/serve.d.ts.map +1 -1
  69. package/dist/types/bin/commands/start.d.ts.map +1 -1
  70. package/dist/types/build/config.d.ts.map +1 -1
  71. package/dist/types/build/index.d.ts.map +1 -1
  72. package/dist/types/build/plugin.d.ts.map +1 -1
  73. package/dist/types/build/stacktrace.d.ts +1 -12
  74. package/dist/types/build/stacktrace.d.ts.map +1 -1
  75. package/dist/types/config/index.d.ts +12 -2
  76. package/dist/types/config/index.d.ts.map +1 -1
  77. package/dist/types/database/index.d.ts.map +1 -1
  78. package/dist/types/index.d.ts +1 -0
  79. package/dist/types/index.d.ts.map +1 -1
  80. package/dist/types/indexing/client.d.ts.map +1 -1
  81. package/dist/types/internal/types.d.ts +8 -13
  82. package/dist/types/internal/types.d.ts.map +1 -1
  83. package/dist/types/rpc/actions.d.ts +30 -0
  84. package/dist/types/rpc/actions.d.ts.map +1 -1
  85. package/dist/types/runtime/events.d.ts.map +1 -1
  86. package/dist/types/runtime/filter.d.ts.map +1 -1
  87. package/dist/types/runtime/fragments.d.ts +9 -1
  88. package/dist/types/runtime/fragments.d.ts.map +1 -1
  89. package/dist/types/runtime/historical.d.ts +18 -1
  90. package/dist/types/runtime/historical.d.ts.map +1 -1
  91. package/dist/types/runtime/index.d.ts +1 -0
  92. package/dist/types/runtime/index.d.ts.map +1 -1
  93. package/dist/types/runtime/isolated.d.ts.map +1 -1
  94. package/dist/types/runtime/multichain.d.ts.map +1 -1
  95. package/dist/types/runtime/omnichain.d.ts.map +1 -1
  96. package/dist/types/runtime/realtime.d.ts.map +1 -1
  97. package/dist/types/server/index.d.ts.map +1 -1
  98. package/dist/types/sync-historical/in-memory.d.ts +24 -0
  99. package/dist/types/sync-historical/in-memory.d.ts.map +1 -0
  100. package/dist/types/sync-historical/index.d.ts.map +1 -1
  101. package/dist/types/sync-realtime/index.d.ts +3 -2
  102. package/dist/types/sync-realtime/index.d.ts.map +1 -1
  103. package/dist/types/sync-store/encode.d.ts.map +1 -1
  104. package/dist/types/sync-store/index.d.ts +3 -3
  105. package/dist/types/sync-store/index.d.ts.map +1 -1
  106. package/dist/types/sync-store/schema.d.ts +63 -98
  107. package/dist/types/sync-store/schema.d.ts.map +1 -1
  108. package/dist/types/types/eth.d.ts +2 -8
  109. package/dist/types/types/eth.d.ts.map +1 -1
  110. package/dist/types/utils/finality.d.ts +12 -9
  111. package/dist/types/utils/finality.d.ts.map +1 -1
  112. package/dist/types/utils/pglite.d.ts +0 -18
  113. package/dist/types/utils/pglite.d.ts.map +1 -1
  114. package/package.json +5 -11
  115. package/src/bin/commands/codegen.ts +3 -3
  116. package/src/bin/commands/dev.ts +3 -3
  117. package/src/bin/commands/serve.ts +3 -3
  118. package/src/bin/commands/start.ts +3 -3
  119. package/src/build/config.ts +29 -28
  120. package/src/build/index.ts +88 -71
  121. package/src/build/plugin.ts +6 -0
  122. package/src/build/stacktrace.ts +38 -65
  123. package/src/config/index.ts +12 -2
  124. package/src/database/index.ts +132 -89
  125. package/src/index.ts +5 -0
  126. package/src/indexing/client.ts +56 -40
  127. package/src/indexing/index.ts +4 -1
  128. package/src/internal/types.ts +10 -13
  129. package/src/rpc/actions.ts +211 -77
  130. package/src/runtime/events.ts +40 -19
  131. package/src/runtime/filter.ts +11 -11
  132. package/src/runtime/fragments.ts +70 -26
  133. package/src/runtime/historical.ts +314 -97
  134. package/src/runtime/index.ts +27 -14
  135. package/src/runtime/isolated.ts +1 -0
  136. package/src/runtime/multichain.ts +1 -0
  137. package/src/runtime/omnichain.ts +1 -0
  138. package/src/runtime/realtime.ts +24 -25
  139. package/src/server/index.ts +14 -7
  140. package/src/sync-historical/in-memory.ts +834 -0
  141. package/src/sync-historical/index.ts +76 -120
  142. package/src/sync-realtime/index.ts +73 -133
  143. package/src/sync-store/encode.ts +1 -6
  144. package/src/sync-store/index.ts +90 -95
  145. package/src/sync-store/schema.ts +24 -27
  146. package/src/types/eth.ts +2 -8
  147. package/src/utils/finality.ts +67 -34
  148. package/src/utils/pglite.ts +0 -79
  149. package/dist/esm/sync-store/migrations.js +0 -1595
  150. package/dist/esm/sync-store/migrations.js.map +0 -1
  151. package/dist/types/sync-store/migrations.d.ts +0 -8
  152. package/dist/types/sync-store/migrations.d.ts.map +0 -1
  153. package/src/sync-store/migrations.ts +0 -1801
@@ -14,13 +14,13 @@ import type {
14
14
  BlockFilter,
15
15
  Chain,
16
16
  Factory,
17
+ FactoryFragmentId,
17
18
  FactoryId,
18
19
  LogFilter,
19
20
  SyncBlock,
20
21
  SyncLog,
21
22
  SyncTrace,
22
23
  SyncTransaction,
23
- SyncTransactionReceipt,
24
24
  TraceFilter,
25
25
  TransactionFilter,
26
26
  TransferFilter,
@@ -28,9 +28,8 @@ import type {
28
28
  import {
29
29
  debug_traceBlockByNumber,
30
30
  eth_getBlockByNumber,
31
- eth_getBlockReceipts,
32
31
  eth_getLogs,
33
- eth_getTransactionReceipt,
32
+ eth_getTransactionReceipts,
34
33
  validateLogsAndBlock,
35
34
  validateReceiptsAndBlock,
36
35
  validateTracesAndBlock,
@@ -50,8 +49,8 @@ import {
50
49
  isTransferFilterMatched,
51
50
  mergeLogFiltersToRequests,
52
51
  } from "@/runtime/filter.js";
52
+ import { getFactoryFragmentId } from "@/runtime/fragments.js";
53
53
  import type {
54
- ChildAddresses,
55
54
  IntervalWithFactory,
56
55
  IntervalWithFilter,
57
56
  } from "@/runtime/index.js";
@@ -100,11 +99,6 @@ type CreateHistoricalSyncParameters = {
100
99
  export const createHistoricalSync = (
101
100
  args: CreateHistoricalSyncParameters,
102
101
  ): HistoricalSync => {
103
- /**
104
- * Flag to fetch transaction receipts through eth_getBlockReceipts (true) or eth_getTransactionReceipt (false)
105
- */
106
- let isBlockReceipts = true;
107
-
108
102
  /**
109
103
  * Data about the range passed to "eth_getLogs" share among all log
110
104
  * filters and log factories.
@@ -222,95 +216,16 @@ export const createHistoricalSync = (
222
216
  return logs;
223
217
  };
224
218
 
225
- const syncTransactionReceipts = async (
226
- block: SyncBlock,
227
- transactionHashes: Set<Hash>,
228
- context?: Parameters<Rpc["request"]>[1],
229
- ): Promise<SyncTransactionReceipt[]> => {
230
- if (transactionHashes.size === 0) {
231
- return [];
232
- }
233
-
234
- if (isBlockReceipts === false) {
235
- const transactionReceipts = await Promise.all(
236
- Array.from(transactionHashes).map(async (hash) => {
237
- const receipt = await eth_getTransactionReceipt(
238
- args.rpc,
239
- [hash],
240
- context,
241
- );
242
-
243
- validateReceiptsAndBlock(
244
- [receipt],
245
- block,
246
- {
247
- method: "eth_getTransactionReceipt",
248
- params: [hash],
249
- },
250
- {
251
- method: "eth_getBlockByNumber",
252
- params: [block.number, true],
253
- },
254
- );
255
-
256
- return receipt;
257
- }),
258
- );
259
-
260
- return transactionReceipts;
261
- }
262
-
263
- let blockReceipts: SyncTransactionReceipt[];
264
- try {
265
- blockReceipts = await eth_getBlockReceipts(
266
- args.rpc,
267
- [block.hash],
268
- context,
269
- );
270
- } catch (_error) {
271
- const error = _error as Error;
272
- args.common.logger.warn({
273
- msg: "Caught eth_getBlockReceipts error, switching to eth_getTransactionReceipt method",
274
- action: "fetch_block_data",
275
- chain: args.chain.name,
276
- chain_id: args.chain.id,
277
- error,
278
- });
279
-
280
- isBlockReceipts = false;
281
- return syncTransactionReceipts(block, transactionHashes, context);
282
- }
283
-
284
- validateReceiptsAndBlock(
285
- blockReceipts,
286
- block,
287
- {
288
- method: "eth_getBlockReceipts",
289
- params: [block.hash],
290
- },
291
- {
292
- method: "eth_getBlockByNumber",
293
- params: [block.number, true],
294
- },
295
- );
296
-
297
- const transactionReceipts = blockReceipts.filter((receipt) =>
298
- transactionHashes.has(receipt.transactionHash),
299
- );
300
-
301
- return transactionReceipts;
302
- };
303
-
304
219
  /**
305
220
  * Fetch child addresses for `factory` within `interval`
306
221
  *
307
- * @dev Newly fetched child addresses are added into `args.childAddresses`
222
+ * @dev Fetched child addresses are added into `args.childAddresses`
308
223
  */
309
224
  const syncAddressFactory = async (
310
225
  factory: Factory,
311
226
  interval: Interval,
312
227
  context?: Parameters<Rpc["request"]>[1],
313
- ): Promise<Map<Address, number>> => {
228
+ ): Promise<Map<FactoryFragmentId, Map<Address, number>>> => {
314
229
  const logs = await syncLogsDynamic(
315
230
  {
316
231
  address: factory.address,
@@ -321,7 +236,7 @@ export const createHistoricalSync = (
321
236
  context,
322
237
  );
323
238
 
324
- const childAddresses = new Map<Address, number>();
239
+ const childAddresses = new Map<FactoryFragmentId, Map<Address, number>>();
325
240
  const factoryChildAddresses = args.childAddresses.get(factory.id)!;
326
241
 
327
242
  const childAddressDecodeFailureIds = new Set<string>();
@@ -355,15 +270,31 @@ export const createHistoricalSync = (
355
270
  throw error;
356
271
  }
357
272
  }
358
- const existingBlockNumber = factoryChildAddresses.get(address);
359
- const newBlockNumber = hexToNumber(log.blockNumber);
273
+ const blockNumber = hexToNumber(log.blockNumber);
274
+
275
+ // Note: Child addresses are stored per parent, so a child address that is
276
+ // already known from a different parent must also be stored for this parent.
277
+
278
+ const fragmentId = getFactoryFragmentId(factory, log.address);
279
+ if (childAddresses.has(fragmentId) === false) {
280
+ childAddresses.set(fragmentId, new Map());
281
+ }
282
+ const fragmentChildAddresses = childAddresses.get(fragmentId)!;
283
+
284
+ const fragmentBlockNumber = fragmentChildAddresses.get(address);
285
+ if (
286
+ fragmentBlockNumber === undefined ||
287
+ fragmentBlockNumber > blockNumber
288
+ ) {
289
+ fragmentChildAddresses.set(address, blockNumber);
290
+ }
360
291
 
292
+ const existingBlockNumber = factoryChildAddresses.get(address);
361
293
  if (
362
294
  existingBlockNumber === undefined ||
363
- existingBlockNumber > newBlockNumber
295
+ existingBlockNumber > blockNumber
364
296
  ) {
365
- childAddresses.set(address, newBlockNumber);
366
- factoryChildAddresses.set(address, newBlockNumber);
297
+ factoryChildAddresses.set(address, blockNumber);
367
298
  }
368
299
  }
369
300
  }
@@ -390,7 +321,7 @@ export const createHistoricalSync = (
390
321
  logger: args.common.logger.child({ action: "fetch_block_data" }),
391
322
  };
392
323
  const endClock = startClock();
393
- const childAddresses: ChildAddresses = new Map();
324
+ const childAddresses = new Map<FactoryFragmentId, Map<Address, number>>();
394
325
 
395
326
  // Dedupe factory intervals by factory id
396
327
 
@@ -418,10 +349,33 @@ export const createHistoricalSync = (
418
349
 
419
350
  await Promise.all(
420
351
  requiredFactoryIntervals.map(async ({ factory, interval }) => {
421
- childAddresses.set(
422
- factory.id,
423
- await syncAddressFactory(factory, interval, context)!,
352
+ const factoryChildAddresses = await syncAddressFactory(
353
+ factory,
354
+ interval,
355
+ context,
424
356
  );
357
+
358
+ // Note: Factories can share a `factory_log` fragment.
359
+
360
+ for (const [
361
+ fragmentId,
362
+ fragmentChildAddresses,
363
+ ] of factoryChildAddresses) {
364
+ if (childAddresses.has(fragmentId) === false) {
365
+ childAddresses.set(fragmentId, fragmentChildAddresses);
366
+ continue;
367
+ }
368
+
369
+ const existing = childAddresses.get(fragmentId)!;
370
+ for (const [address, blockNumber] of fragmentChildAddresses) {
371
+ if (
372
+ existing.has(address) === false ||
373
+ existing.get(address)! > blockNumber
374
+ ) {
375
+ existing.set(address, blockNumber);
376
+ }
377
+ }
378
+ }
425
379
  }),
426
380
  );
427
381
 
@@ -478,18 +432,9 @@ export const createHistoricalSync = (
478
432
  ["chain", "block_range"],
479
433
  );
480
434
 
481
- await promiseAllSettledWithThrow(
482
- Array.from(childAddresses.entries()).map(
483
- ([factoryId, childAddresses]) =>
484
- syncStore.insertChildAddresses(
485
- {
486
- factory: factoryIntervalsById.get(factoryId)!.factory,
487
- childAddresses,
488
- chainId: args.chain.id,
489
- },
490
- context,
491
- ),
492
- ),
435
+ await syncStore.insertChildAddresses(
436
+ { childAddresses, chainId: args.chain.id },
437
+ context,
493
438
  );
494
439
 
495
440
  return logs;
@@ -839,9 +784,24 @@ export const createHistoricalSync = (
839
784
  // Transaction Receipts
840
785
  ////////
841
786
 
842
- const transactionReceipts = await syncTransactionReceipts(
843
- block,
844
- requiredTransactionReceipts,
787
+ const receiptResponses = await eth_getTransactionReceipts(
788
+ args.rpc,
789
+ {
790
+ blockHash: block.hash,
791
+ transactionHashes: requiredTransactionReceipts,
792
+ },
793
+ context,
794
+ );
795
+ const transactionReceipts = receiptResponses.flatMap(
796
+ ({ receipts, request }) => {
797
+ validateReceiptsAndBlock(receipts, block, request, {
798
+ method: "eth_getBlockByNumber",
799
+ params: [block.number, true],
800
+ });
801
+ return receipts.filter((receipt) =>
802
+ requiredTransactionReceipts.has(receipt.transactionHash),
803
+ );
804
+ },
845
805
  );
846
806
 
847
807
  blockCount += 1;
@@ -879,11 +839,7 @@ export const createHistoricalSync = (
879
839
  let receiptCount = 0;
880
840
  let traceCount = 0;
881
841
 
882
- // Same memory usage as `sync-realtime`.
883
- const MAX_BLOCKS_IN_MEM = Math.max(
884
- args.chain.finalityBlockCount * 2,
885
- 100,
886
- );
842
+ const MAX_BLOCKS_IN_MEM = 100;
887
843
 
888
844
  if (requiredIntervals.length > 0) {
889
845
  const queue = createQueue({
@@ -12,6 +12,7 @@ import type {
12
12
  Chain,
13
13
  EventCallback,
14
14
  Factory,
15
+ FactoryFragmentId,
15
16
  FactoryId,
16
17
  Filter,
17
18
  LightBlock,
@@ -30,9 +31,8 @@ import {
30
31
  debug_traceBlockByHash,
31
32
  eth_getBlockByHash,
32
33
  eth_getBlockByNumber,
33
- eth_getBlockReceipts,
34
34
  eth_getLogs,
35
- eth_getTransactionReceipt,
35
+ eth_getTransactionReceipts,
36
36
  validateLogsAndBlock,
37
37
  validateReceiptsAndBlock,
38
38
  validateTracesAndBlock,
@@ -51,6 +51,10 @@ import {
51
51
  isTransactionFilterMatched,
52
52
  isTransferFilterMatched,
53
53
  } from "@/runtime/filter.js";
54
+ import {
55
+ getFactoryFragmentId,
56
+ getFactoryFragmentIds,
57
+ } from "@/runtime/fragments.js";
54
58
  import type { SyncProgress } from "@/runtime/index.js";
55
59
  import { isAsyncExecutionChain } from "@/utils/finality.js";
56
60
  import { createLock } from "@/utils/mutex.js";
@@ -79,7 +83,8 @@ export type BlockWithEventData = {
79
83
  transactionReceipts: SyncTransactionReceipt[];
80
84
  logs: SyncLog[];
81
85
  traces: SyncTrace[];
82
- childAddresses: Map<Factory, Set<Address>>;
86
+ /** Child addresses found in the block per `factory_log` fragment ID. */
87
+ childAddresses: Map<FactoryFragmentId, Set<Address>>;
83
88
  };
84
89
 
85
90
  export type RealtimeSyncEvent =
@@ -106,7 +111,6 @@ const MAX_QUEUED_BLOCKS = 50;
106
111
  export const createRealtimeSync = (
107
112
  args: CreateRealtimeSyncParameters,
108
113
  ): RealtimeSync => {
109
- let isBlockReceipts = true;
110
114
  let finalizedBlock: LightBlock = args.syncProgress.finalized;
111
115
  const childAddresses = args.childAddresses;
112
116
  /** Annotates `childAddresses` for efficient lookup by block number */
@@ -129,6 +133,7 @@ export const createRealtimeSync = (
129
133
 
130
134
  const factories: Factory[] = [];
131
135
  const factoryIds = new Set<FactoryId>();
136
+ const factoryFragmentIds = new Map<Factory, FactoryFragmentId[]>();
132
137
  const logFilters: LogFilter[] = [];
133
138
  const traceFilters: TraceFilter[] = [];
134
139
  const transactionFilters: TransactionFilter[] = [];
@@ -167,104 +172,10 @@ export const createRealtimeSync = (
167
172
  if (factoryIds.has(factory.id)) continue;
168
173
  factoryIds.add(factory.id);
169
174
  factories.push(factory);
175
+ factoryFragmentIds.set(factory, getFactoryFragmentIds(factory));
170
176
  }
171
177
  }
172
178
 
173
- const syncTransactionReceipts = async (
174
- block: SyncBlock,
175
- transactionHashes: Set<Hash>,
176
- ethGetBlockMethod: "eth_getBlockByHash" | "eth_getBlockByNumber",
177
- context?: Parameters<Rpc["request"]>[1],
178
- ): Promise<SyncTransactionReceipt[]> => {
179
- if (transactionHashes.size === 0) {
180
- return [];
181
- }
182
-
183
- if (isBlockReceipts === false) {
184
- const transactionReceipts = await Promise.all(
185
- Array.from(transactionHashes).map(async (hash) => {
186
- const receipt = await eth_getTransactionReceipt(
187
- args.rpc,
188
- [hash],
189
- context,
190
- );
191
-
192
- validateReceiptsAndBlock(
193
- [receipt],
194
- block,
195
- {
196
- method: "eth_getTransactionReceipt",
197
- params: [hash],
198
- },
199
- ethGetBlockMethod === "eth_getBlockByNumber"
200
- ? {
201
- method: "eth_getBlockByNumber",
202
- params: [block.number, true],
203
- }
204
- : {
205
- method: "eth_getBlockByHash",
206
- params: [block.hash, true],
207
- },
208
- );
209
-
210
- return receipt;
211
- }),
212
- );
213
-
214
- return transactionReceipts;
215
- }
216
-
217
- let blockReceipts: SyncTransactionReceipt[];
218
- try {
219
- blockReceipts = await eth_getBlockReceipts(
220
- args.rpc,
221
- [block.hash],
222
- context,
223
- );
224
- } catch (_error) {
225
- const error = _error as Error;
226
- args.common.logger.warn({
227
- msg: "Caught eth_getBlockReceipts error, switching to eth_getTransactionReceipt method",
228
- action: "fetch block data",
229
- chain: args.chain.name,
230
- chain_id: args.chain.id,
231
- error,
232
- });
233
-
234
- isBlockReceipts = false;
235
- return syncTransactionReceipts(
236
- block,
237
- transactionHashes,
238
- ethGetBlockMethod,
239
- context,
240
- );
241
- }
242
-
243
- validateReceiptsAndBlock(
244
- blockReceipts,
245
- block,
246
- {
247
- method: "eth_getBlockReceipts",
248
- params: [block.hash],
249
- },
250
- ethGetBlockMethod === "eth_getBlockByNumber"
251
- ? {
252
- method: "eth_getBlockByNumber",
253
- params: [block.number, true],
254
- }
255
- : {
256
- method: "eth_getBlockByHash",
257
- params: [block.hash, true],
258
- },
259
- );
260
-
261
- const transactionReceipts = blockReceipts.filter((receipt) =>
262
- transactionHashes.has(receipt.transactionHash),
263
- );
264
-
265
- return transactionReceipts;
266
- };
267
-
268
179
  const getLatestUnfinalizedBlock = () => {
269
180
  if (unfinalizedBlocks.length === 0) {
270
181
  return finalizedBlock;
@@ -475,14 +386,13 @@ export const createRealtimeSync = (
475
386
  ////////
476
387
 
477
388
  // Record `blockChildAddresses` that contain factory child addresses
478
- const blockChildAddresses = new Map<Factory, Set<Address>>();
389
+ const blockChildAddresses: BlockWithEventData["childAddresses"] = new Map();
479
390
 
480
391
  const childAddressDecodeFailureIds = new Set<string>();
481
392
  let childAddressDecodeFailureCount = 0;
482
393
  let childAddressDecodeSuccessCount = 0;
483
394
 
484
395
  for (const factory of factories) {
485
- blockChildAddresses.set(factory, new Set<Address>());
486
396
  for (const log of logs) {
487
397
  if (isLogFactoryMatched({ factory, log })) {
488
398
  let address: Address;
@@ -510,7 +420,11 @@ export const createRealtimeSync = (
510
420
  throw error;
511
421
  }
512
422
  }
513
- blockChildAddresses.get(factory)!.add(address);
423
+ const fragmentId = getFactoryFragmentId(factory, log.address);
424
+ if (blockChildAddresses.has(fragmentId) === false) {
425
+ blockChildAddresses.set(fragmentId, new Set());
426
+ }
427
+ blockChildAddresses.get(fragmentId)!.add(address);
514
428
  }
515
429
  }
516
430
  }
@@ -659,12 +573,26 @@ export const createRealtimeSync = (
659
573
  // Transaction Receipts
660
574
  ////////
661
575
 
662
- const transactionReceipts = await syncTransactionReceipts(
663
- block,
664
- requiredTransactionReceipts,
665
- ethGetBlockMethod,
576
+ const receiptResponses = await eth_getTransactionReceipts(
577
+ args.rpc,
578
+ { blockHash: block.hash, transactionHashes: requiredTransactionReceipts },
666
579
  context,
667
580
  );
581
+ const transactionReceipts = receiptResponses.flatMap(
582
+ ({ receipts, request }) => {
583
+ validateReceiptsAndBlock(
584
+ receipts,
585
+ block,
586
+ request,
587
+ ethGetBlockMethod === "eth_getBlockByNumber"
588
+ ? { method: "eth_getBlockByNumber", params: [block.number, true] }
589
+ : { method: "eth_getBlockByHash", params: [block.hash, true] },
590
+ );
591
+ return receipts.filter((receipt) =>
592
+ requiredTransactionReceipts.has(receipt.transactionHash),
593
+ );
594
+ },
595
+ );
668
596
 
669
597
  let childAddressCount = 0;
670
598
  for (const childAddresses of blockChildAddresses.values()) {
@@ -712,15 +640,17 @@ export const createRealtimeSync = (
712
640
  matchedFilters: Set<Filter>;
713
641
  } => {
714
642
  // Update `childAddresses`
715
- for (const factory of factories) {
716
- const knownAddresses = childAddresses.get(factory.id)!;
717
- const blockAddresses = blockChildAddresses.get(factory)!;
718
- for (const address of blockAddresses) {
719
- // Retain only addresses first discovered in this block in the persistence and reorg delta.
720
- if (knownAddresses.has(address)) {
721
- blockAddresses.delete(address);
722
- } else {
723
- knownAddresses.set(address, hexToNumber(block.number));
643
+ if (blockChildAddresses.size > 0) {
644
+ for (const factory of factories) {
645
+ const knownAddresses = childAddresses.get(factory.id)!;
646
+ for (const fragmentId of factoryFragmentIds.get(factory)!) {
647
+ const blockAddresses = blockChildAddresses.get(fragmentId);
648
+ if (blockAddresses === undefined) continue;
649
+ for (const address of blockAddresses) {
650
+ if (knownAddresses.has(address) === false) {
651
+ knownAddresses.set(address, hexToNumber(block.number));
652
+ }
653
+ }
724
654
  }
725
655
  }
726
656
  }
@@ -964,15 +894,21 @@ export const createRealtimeSync = (
964
894
 
965
895
  // remove reorged blocks from `childAddresses`
966
896
  for (const block of reorgedBlocks) {
897
+ const blockNumber = hexToNumber(block.number);
898
+ const blockChildAddresses = childAddressesPerBlock.get(blockNumber)!;
967
899
  for (const factory of factories) {
968
- const addresses = childAddressesPerBlock
969
- .get(hexToNumber(block.number))!
970
- .get(factory)!;
971
- for (const address of addresses) {
972
- childAddresses.get(factory.id)!.delete(address);
900
+ const knownAddresses = childAddresses.get(factory.id)!;
901
+ for (const fragmentId of factoryFragmentIds.get(factory)!) {
902
+ const blockAddresses = blockChildAddresses.get(fragmentId);
903
+ if (blockAddresses === undefined) continue;
904
+ for (const address of blockAddresses) {
905
+ if (knownAddresses.get(address) === blockNumber) {
906
+ knownAddresses.delete(address);
907
+ }
908
+ }
973
909
  }
974
910
  }
975
- childAddressesPerBlock.delete(hexToNumber(block.number));
911
+ childAddressesPerBlock.delete(blockNumber);
976
912
  }
977
913
 
978
914
  return {
@@ -1156,20 +1092,24 @@ export const createRealtimeSync = (
1156
1092
  blockCallback,
1157
1093
  };
1158
1094
 
1159
- // Determine if a new range has become finalized by evaluating if the
1160
- // latest block number is 2 * finalityBlockCount >= finalized block number.
1161
- // Essentially, there is a range the width of finalityBlockCount that is entirely
1162
- // finalized.
1163
-
1095
+ // Finalize the oldest contiguous blocks that are outside the timestamp
1096
+ // based reorg window.
1164
1097
  const blockMovesFinality =
1165
- hexToNumber(block.number) >=
1166
- hexToNumber(finalizedBlock.number) + 2 * args.chain.finalityBlockCount;
1098
+ hexToNumber(block.timestamp) -
1099
+ hexToNumber(unfinalizedBlocks[0]!.timestamp) >=
1100
+ args.chain.reorgWindow;
1167
1101
  if (blockMovesFinality) {
1168
- const pendingFinalizedBlock = unfinalizedBlocks.find(
1169
- (lb) =>
1170
- hexToNumber(lb.number) ===
1171
- hexToNumber(block.number) - args.chain.finalityBlockCount,
1172
- )!;
1102
+ let pendingFinalizedBlock = unfinalizedBlocks[0]!;
1103
+ for (const candidate of unfinalizedBlocks) {
1104
+ if (
1105
+ hexToNumber(block.timestamp) - hexToNumber(candidate.timestamp) >=
1106
+ args.chain.reorgWindow
1107
+ ) {
1108
+ pendingFinalizedBlock = candidate;
1109
+ } else {
1110
+ break;
1111
+ }
1112
+ }
1173
1113
 
1174
1114
  args.common.logger.debug({
1175
1115
  msg: "Removed finalized blocks from local chain",
@@ -136,7 +136,7 @@ export const encodeTrace = ({
136
136
  chainId: BigInt(chainId),
137
137
  blockNumber: hexToBigInt(block.number),
138
138
  transactionIndex: hexToNumber(transaction.transactionIndex),
139
- traceIndex: trace.trace.index,
139
+ traceAddress: trace.trace.traceAddress,
140
140
  from: toLowerCase(trace.trace.from),
141
141
  to: trace.trace.to ? toLowerCase(trace.trace.to) : null,
142
142
  input: trace.trace.input,
@@ -145,9 +145,4 @@ export const encodeTrace = ({
145
145
  type: trace.trace.type,
146
146
  gas: hexToBigInt(trace.trace.gas),
147
147
  gasUsed: hexToBigInt(trace.trace.gasUsed),
148
- error: trace.trace.error ? trace.trace.error.replace(/\0/g, "") : null,
149
- revertReason: trace.trace.revertReason
150
- ? trace.trace.revertReason.replace(/\0/g, "")
151
- : null,
152
- subcalls: trace.trace.subcalls,
153
148
  });