ponder 0.14.13 → 0.15.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 (237) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/esm/bin/commands/createViews.js +28 -11
  3. package/dist/esm/bin/commands/createViews.js.map +1 -1
  4. package/dist/esm/bin/commands/dev.js +42 -22
  5. package/dist/esm/bin/commands/dev.js.map +1 -1
  6. package/dist/esm/bin/commands/prune.js +3 -0
  7. package/dist/esm/bin/commands/prune.js.map +1 -1
  8. package/dist/esm/bin/commands/serve.js +4 -1
  9. package/dist/esm/bin/commands/serve.js.map +1 -1
  10. package/dist/esm/bin/commands/start.js +18 -6
  11. package/dist/esm/bin/commands/start.js.map +1 -1
  12. package/dist/esm/bin/isolatedController.js +200 -0
  13. package/dist/esm/bin/isolatedController.js.map +1 -0
  14. package/dist/esm/bin/isolatedWorker.js +146 -0
  15. package/dist/esm/bin/isolatedWorker.js.map +1 -0
  16. package/dist/esm/build/config.js +322 -402
  17. package/dist/esm/build/config.js.map +1 -1
  18. package/dist/esm/build/index.js +8 -11
  19. package/dist/esm/build/index.js.map +1 -1
  20. package/dist/esm/build/pre.js +1 -4
  21. package/dist/esm/build/pre.js.map +1 -1
  22. package/dist/esm/build/schema.js +25 -3
  23. package/dist/esm/build/schema.js.map +1 -1
  24. package/dist/esm/client/index.js +306 -42
  25. package/dist/esm/client/index.js.map +1 -1
  26. package/dist/esm/database/actions.js +264 -104
  27. package/dist/esm/database/actions.js.map +1 -1
  28. package/dist/esm/database/index.js +39 -33
  29. package/dist/esm/database/index.js.map +1 -1
  30. package/dist/esm/database/queryBuilder.js +1 -0
  31. package/dist/esm/database/queryBuilder.js.map +1 -1
  32. package/dist/esm/drizzle/index.js +11 -7
  33. package/dist/esm/drizzle/index.js.map +1 -1
  34. package/dist/esm/drizzle/onchain.js +18 -0
  35. package/dist/esm/drizzle/onchain.js.map +1 -1
  36. package/dist/esm/indexing/client.js +32 -25
  37. package/dist/esm/indexing/client.js.map +1 -1
  38. package/dist/esm/indexing/index.js +110 -178
  39. package/dist/esm/indexing/index.js.map +1 -1
  40. package/dist/esm/indexing/profile.js +1 -1
  41. package/dist/esm/indexing/profile.js.map +1 -1
  42. package/dist/esm/indexing-store/cache.js +196 -274
  43. package/dist/esm/indexing-store/cache.js.map +1 -1
  44. package/dist/esm/indexing-store/historical.js +17 -13
  45. package/dist/esm/indexing-store/historical.js.map +1 -1
  46. package/dist/esm/indexing-store/index.js +10 -1
  47. package/dist/esm/indexing-store/index.js.map +1 -1
  48. package/dist/esm/indexing-store/profile.js +3 -3
  49. package/dist/esm/indexing-store/profile.js.map +1 -1
  50. package/dist/esm/indexing-store/realtime.js +27 -2
  51. package/dist/esm/indexing-store/realtime.js.map +1 -1
  52. package/dist/esm/internal/errors.js +28 -0
  53. package/dist/esm/internal/errors.js.map +1 -1
  54. package/dist/esm/internal/metrics.js +279 -82
  55. package/dist/esm/internal/metrics.js.map +1 -1
  56. package/dist/esm/internal/options.js +1 -0
  57. package/dist/esm/internal/options.js.map +1 -1
  58. package/dist/esm/internal/telemetry.js +1 -1
  59. package/dist/esm/internal/telemetry.js.map +1 -1
  60. package/dist/esm/rpc/http.js +130 -0
  61. package/dist/esm/rpc/http.js.map +1 -0
  62. package/dist/esm/rpc/index.js +38 -7
  63. package/dist/esm/rpc/index.js.map +1 -1
  64. package/dist/esm/runtime/events.js +179 -212
  65. package/dist/esm/runtime/events.js.map +1 -1
  66. package/dist/esm/runtime/filter.js +71 -0
  67. package/dist/esm/runtime/filter.js.map +1 -1
  68. package/dist/esm/runtime/fragments.js +78 -73
  69. package/dist/esm/runtime/fragments.js.map +1 -1
  70. package/dist/esm/runtime/historical.js +306 -130
  71. package/dist/esm/runtime/historical.js.map +1 -1
  72. package/dist/esm/runtime/index.js +183 -58
  73. package/dist/esm/runtime/index.js.map +1 -1
  74. package/dist/esm/runtime/isolated.js +462 -0
  75. package/dist/esm/runtime/isolated.js.map +1 -0
  76. package/dist/esm/runtime/multichain.js +80 -73
  77. package/dist/esm/runtime/multichain.js.map +1 -1
  78. package/dist/esm/runtime/omnichain.js +82 -75
  79. package/dist/esm/runtime/omnichain.js.map +1 -1
  80. package/dist/esm/runtime/realtime.js +198 -66
  81. package/dist/esm/runtime/realtime.js.map +1 -1
  82. package/dist/esm/sync-historical/index.js +416 -457
  83. package/dist/esm/sync-historical/index.js.map +1 -1
  84. package/dist/esm/sync-realtime/bloom.js +3 -3
  85. package/dist/esm/sync-realtime/bloom.js.map +1 -1
  86. package/dist/esm/sync-realtime/index.js +27 -46
  87. package/dist/esm/sync-realtime/index.js.map +1 -1
  88. package/dist/esm/sync-store/index.js +112 -63
  89. package/dist/esm/sync-store/index.js.map +1 -1
  90. package/dist/esm/utils/abi.js +20 -32
  91. package/dist/esm/utils/abi.js.map +1 -1
  92. package/dist/esm/utils/chunk.js +8 -0
  93. package/dist/esm/utils/chunk.js.map +1 -0
  94. package/dist/esm/utils/promiseAllSettledWithThrow.js +19 -0
  95. package/dist/esm/utils/promiseAllSettledWithThrow.js.map +1 -0
  96. package/dist/esm/{client/parse.js → utils/sql-parse.js} +94 -80
  97. package/dist/esm/utils/sql-parse.js.map +1 -0
  98. package/dist/types/bin/commands/createViews.d.ts.map +1 -1
  99. package/dist/types/bin/commands/dev.d.ts.map +1 -1
  100. package/dist/types/bin/commands/prune.d.ts.map +1 -1
  101. package/dist/types/bin/commands/serve.d.ts.map +1 -1
  102. package/dist/types/bin/commands/start.d.ts.map +1 -1
  103. package/dist/types/bin/isolatedController.d.ts +13 -0
  104. package/dist/types/bin/isolatedController.d.ts.map +1 -0
  105. package/dist/types/bin/isolatedWorker.d.ts +9 -0
  106. package/dist/types/bin/isolatedWorker.d.ts.map +1 -0
  107. package/dist/types/build/config.d.ts +29 -11
  108. package/dist/types/build/config.d.ts.map +1 -1
  109. package/dist/types/build/index.d.ts +3 -2
  110. package/dist/types/build/index.d.ts.map +1 -1
  111. package/dist/types/build/pre.d.ts +1 -1
  112. package/dist/types/build/pre.d.ts.map +1 -1
  113. package/dist/types/build/schema.d.ts +5 -3
  114. package/dist/types/build/schema.d.ts.map +1 -1
  115. package/dist/types/client/index.d.ts +1 -1
  116. package/dist/types/client/index.d.ts.map +1 -1
  117. package/dist/types/config/index.d.ts +3 -3
  118. package/dist/types/config/index.d.ts.map +1 -1
  119. package/dist/types/database/actions.d.ts +53 -7
  120. package/dist/types/database/actions.d.ts.map +1 -1
  121. package/dist/types/database/index.d.ts +21 -21
  122. package/dist/types/database/index.d.ts.map +1 -1
  123. package/dist/types/database/queryBuilder.d.ts.map +1 -1
  124. package/dist/types/drizzle/index.d.ts +4 -5
  125. package/dist/types/drizzle/index.d.ts.map +1 -1
  126. package/dist/types/drizzle/onchain.d.ts +6 -0
  127. package/dist/types/drizzle/onchain.d.ts.map +1 -1
  128. package/dist/types/indexing/client.d.ts.map +1 -1
  129. package/dist/types/indexing/index.d.ts +2 -5
  130. package/dist/types/indexing/index.d.ts.map +1 -1
  131. package/dist/types/indexing-store/cache.d.ts +3 -2
  132. package/dist/types/indexing-store/cache.d.ts.map +1 -1
  133. package/dist/types/indexing-store/historical.d.ts +2 -1
  134. package/dist/types/indexing-store/historical.d.ts.map +1 -1
  135. package/dist/types/indexing-store/index.d.ts +1 -0
  136. package/dist/types/indexing-store/index.d.ts.map +1 -1
  137. package/dist/types/indexing-store/realtime.d.ts +2 -1
  138. package/dist/types/indexing-store/realtime.d.ts.map +1 -1
  139. package/dist/types/internal/errors.d.ts +5 -0
  140. package/dist/types/internal/errors.d.ts.map +1 -1
  141. package/dist/types/internal/metrics.d.ts +21 -0
  142. package/dist/types/internal/metrics.d.ts.map +1 -1
  143. package/dist/types/internal/options.d.ts +2 -0
  144. package/dist/types/internal/options.d.ts.map +1 -1
  145. package/dist/types/internal/types.d.ts +66 -58
  146. package/dist/types/internal/types.d.ts.map +1 -1
  147. package/dist/types/rpc/http.d.ts +17 -0
  148. package/dist/types/rpc/http.d.ts.map +1 -0
  149. package/dist/types/rpc/index.d.ts.map +1 -1
  150. package/dist/types/runtime/events.d.ts +4 -4
  151. package/dist/types/runtime/events.d.ts.map +1 -1
  152. package/dist/types/runtime/filter.d.ts +5 -1
  153. package/dist/types/runtime/filter.d.ts.map +1 -1
  154. package/dist/types/runtime/fragments.d.ts +4 -3
  155. package/dist/types/runtime/fragments.d.ts.map +1 -1
  156. package/dist/types/runtime/historical.d.ts +29 -13
  157. package/dist/types/runtime/historical.d.ts.map +1 -1
  158. package/dist/types/runtime/index.d.ts +49 -6
  159. package/dist/types/runtime/index.d.ts.map +1 -1
  160. package/dist/types/runtime/init.d.ts +5 -5
  161. package/dist/types/runtime/init.d.ts.map +1 -1
  162. package/dist/types/runtime/isolated.d.ts +14 -0
  163. package/dist/types/runtime/isolated.d.ts.map +1 -0
  164. package/dist/types/runtime/multichain.d.ts.map +1 -1
  165. package/dist/types/runtime/omnichain.d.ts.map +1 -1
  166. package/dist/types/runtime/realtime.d.ts +21 -10
  167. package/dist/types/runtime/realtime.d.ts.map +1 -1
  168. package/dist/types/sync-historical/index.d.ts +18 -8
  169. package/dist/types/sync-historical/index.d.ts.map +1 -1
  170. package/dist/types/sync-realtime/bloom.d.ts.map +1 -1
  171. package/dist/types/sync-realtime/index.d.ts +2 -2
  172. package/dist/types/sync-realtime/index.d.ts.map +1 -1
  173. package/dist/types/sync-store/index.d.ts +9 -9
  174. package/dist/types/sync-store/index.d.ts.map +1 -1
  175. package/dist/types/utils/abi.d.ts +3 -34
  176. package/dist/types/utils/abi.d.ts.map +1 -1
  177. package/dist/types/utils/chunk.d.ts +2 -0
  178. package/dist/types/utils/chunk.d.ts.map +1 -0
  179. package/dist/types/utils/promiseAllSettledWithThrow.d.ts +8 -0
  180. package/dist/types/utils/promiseAllSettledWithThrow.d.ts.map +1 -0
  181. package/dist/types/utils/sql-parse.d.ts +21 -0
  182. package/dist/types/utils/sql-parse.d.ts.map +1 -0
  183. package/package.json +2 -2
  184. package/src/bin/commands/createViews.ts +35 -15
  185. package/src/bin/commands/dev.ts +43 -21
  186. package/src/bin/commands/prune.ts +6 -0
  187. package/src/bin/commands/serve.ts +4 -1
  188. package/src/bin/commands/start.ts +20 -5
  189. package/src/bin/isolatedController.ts +300 -0
  190. package/src/bin/isolatedWorker.ts +192 -0
  191. package/src/build/config.ts +570 -632
  192. package/src/build/index.ts +14 -14
  193. package/src/build/pre.ts +1 -4
  194. package/src/build/schema.ts +49 -4
  195. package/src/client/index.ts +386 -48
  196. package/src/config/index.ts +3 -3
  197. package/src/database/actions.ts +469 -120
  198. package/src/database/index.ts +85 -58
  199. package/src/database/queryBuilder.ts +1 -0
  200. package/src/drizzle/index.ts +15 -7
  201. package/src/drizzle/onchain.ts +19 -0
  202. package/src/indexing/client.ts +38 -25
  203. package/src/indexing/index.ts +137 -230
  204. package/src/indexing/profile.ts +1 -1
  205. package/src/indexing-store/cache.ts +285 -414
  206. package/src/indexing-store/historical.ts +20 -10
  207. package/src/indexing-store/index.ts +16 -0
  208. package/src/indexing-store/profile.ts +3 -3
  209. package/src/indexing-store/realtime.ts +28 -0
  210. package/src/internal/errors.ts +26 -0
  211. package/src/internal/metrics.ts +341 -111
  212. package/src/internal/options.ts +4 -0
  213. package/src/internal/telemetry.ts +1 -1
  214. package/src/internal/types.ts +70 -87
  215. package/src/rpc/http.ts +164 -0
  216. package/src/rpc/index.ts +39 -7
  217. package/src/runtime/events.ts +195 -240
  218. package/src/runtime/filter.ts +85 -1
  219. package/src/runtime/fragments.ts +109 -113
  220. package/src/runtime/historical.ts +467 -189
  221. package/src/runtime/index.ts +337 -69
  222. package/src/runtime/init.ts +5 -5
  223. package/src/runtime/isolated.ts +768 -0
  224. package/src/runtime/multichain.ts +137 -102
  225. package/src/runtime/omnichain.ts +138 -106
  226. package/src/runtime/realtime.ts +322 -123
  227. package/src/sync-historical/index.ts +556 -692
  228. package/src/sync-realtime/bloom.ts +7 -3
  229. package/src/sync-realtime/index.ts +31 -46
  230. package/src/sync-store/index.ts +189 -95
  231. package/src/utils/abi.ts +33 -90
  232. package/src/utils/chunk.ts +7 -0
  233. package/src/utils/promiseAllSettledWithThrow.ts +27 -0
  234. package/src/{client/parse.ts → utils/sql-parse.ts} +100 -90
  235. package/dist/esm/client/parse.js.map +0 -1
  236. package/dist/types/client/parse.d.ts +0 -14
  237. package/dist/types/client/parse.d.ts.map +0 -1
@@ -1,20 +1,20 @@
1
+ import type { Database } from "@/database/index.js";
1
2
  import type { Common } from "@/internal/common.js";
2
3
  import { ShutdownError } from "@/internal/errors.js";
3
4
  import type {
4
5
  Chain,
5
6
  CrashRecoveryCheckpoint,
6
7
  Event,
8
+ EventCallback,
7
9
  IndexingBuild,
8
10
  RawEvent,
9
- Source,
10
11
  SyncBlock,
11
12
  } from "@/internal/types.js";
12
13
  import { _eth_getBlockByNumber } from "@/rpc/actions.js";
13
14
  import type { Rpc } from "@/rpc/index.js";
14
15
  import { buildEvents, decodeEvents } from "@/runtime/events.js";
15
- import { isAddressFactory } from "@/runtime/filter.js";
16
16
  import { createHistoricalSync } from "@/sync-historical/index.js";
17
- import type { SyncStore } from "@/sync-store/index.js";
17
+ import { type SyncStore, createSyncStore } from "@/sync-store/index.js";
18
18
  import {
19
19
  MAX_CHECKPOINT,
20
20
  ZERO_CHECKPOINT,
@@ -22,22 +22,25 @@ import {
22
22
  encodeCheckpoint,
23
23
  min,
24
24
  } from "@/utils/checkpoint.js";
25
+ import { estimate } from "@/utils/estimate.js";
25
26
  import { formatPercentage } from "@/utils/format.js";
26
27
  import {
27
28
  bufferAsyncGenerator,
29
+ createCallbackGenerator,
28
30
  mergeAsyncGenerators,
29
31
  } from "@/utils/generators.js";
30
- import {
31
- type Interval,
32
- intervalDifference,
33
- intervalIntersectionMany,
34
- intervalSum,
35
- intervalUnion,
36
- } from "@/utils/interval.js";
32
+ import { type Interval, intervalSum } from "@/utils/interval.js";
37
33
  import { partition } from "@/utils/partition.js";
34
+ import { promiseWithResolvers } from "@/utils/promiseWithResolvers.js";
38
35
  import { startClock } from "@/utils/timer.js";
39
36
  import { hexToNumber } from "viem";
40
- import type { CachedIntervals, ChildAddresses, SyncProgress } from "./index.js";
37
+ import {
38
+ type CachedIntervals,
39
+ type ChildAddresses,
40
+ type SyncProgress,
41
+ getRequiredIntervals,
42
+ getRequiredIntervalsWithFilters,
43
+ } from "./index.js";
41
44
  import { initEventGenerator, initRefetchEvents } from "./init.js";
42
45
  import { getOmnichainCheckpoint } from "./omnichain.js";
43
46
 
@@ -45,7 +48,7 @@ export async function* getHistoricalEventsOmnichain(params: {
45
48
  common: Common;
46
49
  indexingBuild: Pick<
47
50
  IndexingBuild,
48
- "sources" | "chains" | "rpcs" | "finalizedBlocks"
51
+ "eventCallbacks" | "chains" | "rpcs" | "finalizedBlocks"
49
52
  >;
50
53
  crashRecoveryCheckpoint: CrashRecoveryCheckpoint;
51
54
  perChainSync: Map<
@@ -56,7 +59,7 @@ export async function* getHistoricalEventsOmnichain(params: {
56
59
  cachedIntervals: CachedIntervals;
57
60
  }
58
61
  >;
59
- syncStore: SyncStore;
62
+ database: Database;
60
63
  }): AsyncGenerator<
61
64
  | {
62
65
  type: "events";
@@ -84,9 +87,10 @@ export async function* getHistoricalEventsOmnichain(params: {
84
87
  params.indexingBuild.chains.findIndex((c) => c.id === chain.id)
85
88
  ]!;
86
89
 
87
- const sources = params.indexingBuild.sources.filter(
88
- ({ filter }) => filter.chainId === chain.id,
89
- );
90
+ const eventCallbacks =
91
+ params.indexingBuild.eventCallbacks[
92
+ params.indexingBuild.chains.findIndex((c) => c.id === chain.id)
93
+ ]!;
90
94
 
91
95
  const crashRecoveryCheckpoint = params.crashRecoveryCheckpoint?.find(
92
96
  ({ chainId }) => chainId === chain.id,
@@ -121,7 +125,10 @@ export async function* getHistoricalEventsOmnichain(params: {
121
125
  ) {
122
126
  from = crashRecoveryCheckpoint;
123
127
  } else {
124
- const fromBlock = await params.syncStore.getSafeCrashRecoveryBlock({
128
+ const fromBlock = await createSyncStore({
129
+ common: params.common,
130
+ qb: params.database.syncQB,
131
+ }).getSafeCrashRecoveryBlock({
125
132
  chainId: chain.id,
126
133
  timestamp: Number(
127
134
  decodeCheckpoint(crashRecoveryCheckpoint).blockTimestamp,
@@ -147,12 +154,12 @@ export async function* getHistoricalEventsOmnichain(params: {
147
154
 
148
155
  const events = pendingEvents.filter(
149
156
  (event) =>
150
- event.chainId === chain.id && event.checkpoint <= omnichainTo,
157
+ event.chain.id === chain.id && event.checkpoint <= omnichainTo,
151
158
  );
152
159
 
153
160
  pendingEvents = pendingEvents.filter(
154
161
  (event) =>
155
- (event.chainId === chain.id &&
162
+ (event.chain.id === chain.id &&
156
163
  event.checkpoint <= omnichainTo) === false,
157
164
  );
158
165
 
@@ -193,7 +200,7 @@ export async function* getHistoricalEventsOmnichain(params: {
193
200
  indexingBuild: params.indexingBuild,
194
201
  chain,
195
202
  rpc,
196
- sources,
203
+ eventCallbacks,
197
204
  childAddresses,
198
205
  syncProgress,
199
206
  cachedIntervals,
@@ -204,7 +211,7 @@ export async function* getHistoricalEventsOmnichain(params: {
204
211
  params.common.options.syncEventsQuerySize /
205
212
  (params.indexingBuild.chains.length + 1),
206
213
  ) + 6,
207
- syncStore: params.syncStore,
214
+ database: params.database,
208
215
  isCatchup,
209
216
  });
210
217
 
@@ -215,7 +222,12 @@ export async function* getHistoricalEventsOmnichain(params: {
215
222
  } of eventGenerator) {
216
223
  const endClock = startClock();
217
224
 
218
- let events = decodeEvents(params.common, sources, rawEvents);
225
+ let events = decodeEvents(
226
+ params.common,
227
+ chain,
228
+ eventCallbacks,
229
+ rawEvents,
230
+ );
219
231
 
220
232
  params.common.logger.trace({
221
233
  msg: "Decoded events",
@@ -371,7 +383,7 @@ export async function* getHistoricalEventsMultichain(params: {
371
383
  common: Common;
372
384
  indexingBuild: Pick<
373
385
  IndexingBuild,
374
- "sources" | "chains" | "rpcs" | "finalizedBlocks"
386
+ "eventCallbacks" | "chains" | "rpcs" | "finalizedBlocks"
375
387
  >;
376
388
  crashRecoveryCheckpoint: CrashRecoveryCheckpoint;
377
389
  perChainSync: Map<
@@ -382,7 +394,7 @@ export async function* getHistoricalEventsMultichain(params: {
382
394
  cachedIntervals: CachedIntervals;
383
395
  }
384
396
  >;
385
- syncStore: SyncStore;
397
+ database: Database;
386
398
  }) {
387
399
  let isCatchup = false;
388
400
  let lastUnfinalizedRefetch = Date.now();
@@ -399,9 +411,10 @@ export async function* getHistoricalEventsMultichain(params: {
399
411
  params.indexingBuild.chains.findIndex((c) => c.id === chain.id)
400
412
  ]!;
401
413
 
402
- const sources = params.indexingBuild.sources.filter(
403
- ({ filter }) => filter.chainId === chain.id,
404
- );
414
+ const eventCallbacks =
415
+ params.indexingBuild.eventCallbacks[
416
+ params.indexingBuild.chains.findIndex((c) => c.id === chain.id)
417
+ ]!;
405
418
 
406
419
  const crashRecoveryCheckpoint = params.crashRecoveryCheckpoint?.find(
407
420
  ({ chainId }) => chainId === chain.id,
@@ -426,7 +439,10 @@ export async function* getHistoricalEventsMultichain(params: {
426
439
  ) {
427
440
  from = crashRecoveryCheckpoint;
428
441
  } else {
429
- const fromBlock = await params.syncStore.getSafeCrashRecoveryBlock({
442
+ const fromBlock = await createSyncStore({
443
+ common: params.common,
444
+ qb: params.database.syncQB,
445
+ }).getSafeCrashRecoveryBlock({
430
446
  chainId: chain.id,
431
447
  timestamp: Number(
432
448
  decodeCheckpoint(crashRecoveryCheckpoint).blockTimestamp,
@@ -472,7 +488,7 @@ export async function* getHistoricalEventsMultichain(params: {
472
488
  indexingBuild: params.indexingBuild,
473
489
  chain,
474
490
  rpc,
475
- sources,
491
+ eventCallbacks,
476
492
  childAddresses,
477
493
  syncProgress,
478
494
  cachedIntervals,
@@ -483,7 +499,7 @@ export async function* getHistoricalEventsMultichain(params: {
483
499
  params.common.options.syncEventsQuerySize /
484
500
  (params.indexingBuild.chains.length + 1),
485
501
  ) + 6,
486
- syncStore: params.syncStore,
502
+ database: params.database,
487
503
  isCatchup,
488
504
  });
489
505
 
@@ -494,7 +510,12 @@ export async function* getHistoricalEventsMultichain(params: {
494
510
  } of eventGenerator) {
495
511
  const endClock = startClock();
496
512
 
497
- let events = decodeEvents(params.common, sources, rawEvents);
513
+ let events = decodeEvents(
514
+ params.common,
515
+ chain,
516
+ eventCallbacks,
517
+ rawEvents,
518
+ );
498
519
 
499
520
  params.common.logger.trace({
500
521
  msg: "Decoded events",
@@ -614,25 +635,223 @@ export async function* getHistoricalEventsMultichain(params: {
614
635
  }
615
636
  }
616
637
 
638
+ export async function* getHistoricalEventsIsolated(params: {
639
+ common: Common;
640
+ indexingBuild: Pick<
641
+ IndexingBuild,
642
+ "eventCallbacks" | "chains" | "rpcs" | "finalizedBlocks"
643
+ >;
644
+ crashRecoveryCheckpoint: CrashRecoveryCheckpoint;
645
+ chain: Chain;
646
+ syncProgress: SyncProgress;
647
+ childAddresses: ChildAddresses;
648
+ cachedIntervals: CachedIntervals;
649
+ database: Database;
650
+ }) {
651
+ let isCatchup = false;
652
+ let lastUnfinalizedRefetch = Date.now();
653
+ let cursor: string | undefined;
654
+
655
+ while (true) {
656
+ const rpc =
657
+ params.indexingBuild.rpcs[
658
+ params.indexingBuild.chains.findIndex((c) => c.id === params.chain.id)
659
+ ]!;
660
+
661
+ const eventCallbacks =
662
+ params.indexingBuild.eventCallbacks[
663
+ params.indexingBuild.chains.findIndex((c) => c.id === params.chain.id)
664
+ ]!;
665
+
666
+ const crashRecoveryCheckpoint = params.crashRecoveryCheckpoint?.find(
667
+ ({ chainId }) => chainId === params.chain.id,
668
+ )?.checkpoint;
669
+
670
+ const to = min(
671
+ params.syncProgress.getCheckpoint({ tag: "finalized" }),
672
+ params.syncProgress.getCheckpoint({ tag: "end" }),
673
+ );
674
+ let from: string;
675
+
676
+ if (isCatchup === false) {
677
+ // In order to speed up the "extract" phase when there is a crash recovery,
678
+ // the beginning cursor is moved forwards. This only works when `crashRecoveryCheckpoint`
679
+ // is defined.
680
+
681
+ if (crashRecoveryCheckpoint === undefined) {
682
+ from = params.syncProgress.getCheckpoint({ tag: "start" });
683
+ } else if (
684
+ Number(decodeCheckpoint(crashRecoveryCheckpoint).chainId) ===
685
+ params.chain.id
686
+ ) {
687
+ from = crashRecoveryCheckpoint;
688
+ } else {
689
+ from = params.syncProgress.getCheckpoint({ tag: "start" });
690
+ }
691
+ } else {
692
+ from = encodeCheckpoint({
693
+ ...ZERO_CHECKPOINT,
694
+ blockTimestamp: decodeCheckpoint(cursor!).blockTimestamp,
695
+ chainId: decodeCheckpoint(cursor!).chainId,
696
+ blockNumber: decodeCheckpoint(cursor!).blockNumber + 1n,
697
+ });
698
+
699
+ if (from > to) return;
700
+ }
701
+
702
+ params.common.logger.info({
703
+ msg: "Started backfill indexing",
704
+ chain: params.chain.name,
705
+ chain_id: params.chain.id,
706
+ block_range: JSON.stringify([
707
+ Number(decodeCheckpoint(from).blockNumber),
708
+ Number(decodeCheckpoint(to).blockNumber),
709
+ ]),
710
+ });
711
+
712
+ const eventGenerator = await initEventGenerator({
713
+ common: params.common,
714
+ indexingBuild: params.indexingBuild,
715
+ chain: params.chain,
716
+ rpc,
717
+ eventCallbacks,
718
+ childAddresses: params.childAddresses,
719
+ syncProgress: params.syncProgress,
720
+ cachedIntervals: params.cachedIntervals,
721
+ from,
722
+ to,
723
+ limit:
724
+ Math.round(
725
+ params.common.options.syncEventsQuerySize /
726
+ (params.indexingBuild.chains.length + 1),
727
+ ) + 6,
728
+ database: params.database,
729
+ isCatchup,
730
+ });
731
+
732
+ for await (const {
733
+ events: rawEvents,
734
+ checkpoint,
735
+ blockRange,
736
+ } of eventGenerator) {
737
+ const endClock = startClock();
738
+
739
+ let events = decodeEvents(
740
+ params.common,
741
+ params.chain,
742
+ eventCallbacks,
743
+ rawEvents,
744
+ );
745
+
746
+ params.common.logger.trace({
747
+ msg: "Decoded events",
748
+ chain: params.chain.name,
749
+ chain_id: params.chain.id,
750
+ event_count: events.length,
751
+ duration: endClock(),
752
+ });
753
+
754
+ params.common.metrics.ponder_historical_extract_duration.inc(
755
+ { step: "decode" },
756
+ endClock(),
757
+ );
758
+
759
+ // Removes events that have a checkpoint earlier than (or equal to)
760
+ // the crash recovery checkpoint.
761
+
762
+ if (crashRecoveryCheckpoint) {
763
+ const [left, right] = partition(
764
+ events,
765
+ (event) => event.checkpoint <= crashRecoveryCheckpoint,
766
+ );
767
+ events = right;
768
+
769
+ if (left.length > 0) {
770
+ params.common.logger.trace({
771
+ msg: "Filtered events before crash recovery checkpoint",
772
+ chain: params.chain.name,
773
+ chain_id: params.chain.id,
774
+ event_count: left.length,
775
+ checkpoint: crashRecoveryCheckpoint,
776
+ });
777
+ }
778
+ }
779
+
780
+ yield { chainId: params.chain.id, events, checkpoint, blockRange };
781
+ }
782
+
783
+ cursor = to;
784
+
785
+ if (Date.now() - lastUnfinalizedRefetch < 30_000) {
786
+ break;
787
+ }
788
+ lastUnfinalizedRefetch = Date.now();
789
+
790
+ const context = {
791
+ logger: params.common.logger.child({ action: "refetch_finalized_block" }),
792
+ };
793
+
794
+ const endClock = startClock();
795
+
796
+ const finalizedBlock = await _eth_getBlockByNumber(
797
+ rpc,
798
+ { blockTag: "latest" },
799
+ context,
800
+ ).then((latest) =>
801
+ _eth_getBlockByNumber(
802
+ rpc,
803
+ {
804
+ blockNumber: Math.max(
805
+ hexToNumber(latest.number) - params.chain.finalityBlockCount,
806
+ 0,
807
+ ),
808
+ },
809
+ context,
810
+ ),
811
+ );
812
+
813
+ const finalizedBlockNumber = hexToNumber(finalizedBlock.number);
814
+ params.common.logger.debug({
815
+ msg: "Refetched finalized block for backfill cutover",
816
+ chain: params.chain.name,
817
+ chain_id: params.chain.id,
818
+ finalized_block: finalizedBlockNumber,
819
+ duration: endClock(),
820
+ });
821
+
822
+ if (
823
+ hexToNumber(finalizedBlock.number) -
824
+ hexToNumber(params.syncProgress.finalized.number) <=
825
+ params.chain.finalityBlockCount
826
+ ) {
827
+ break;
828
+ }
829
+
830
+ params.syncProgress.finalized = finalizedBlock;
831
+ isCatchup = true;
832
+ }
833
+ }
834
+
617
835
  export async function refetchHistoricalEvents(params: {
618
836
  common: Common;
619
- indexingBuild: Pick<IndexingBuild, "sources" | "chains">;
837
+ indexingBuild: Pick<IndexingBuild, "eventCallbacks" | "chains">;
620
838
  perChainSync: Map<Chain, { childAddresses: ChildAddresses }>;
621
839
  events: Event[];
622
840
  syncStore: SyncStore;
623
841
  }): Promise<Event[]> {
624
842
  const events: Event[] = new Array(params.events.length);
625
843
 
626
- for (const chain of PONDER_INDEXING_BUILD.chains) {
844
+ for (const chain of params.indexingBuild.chains) {
627
845
  const { childAddresses } = params.perChainSync.get(chain)!;
628
846
 
629
847
  // Note: All filters are refetched, no matter if they are resolved or not.
630
- const sources = params.indexingBuild.sources.filter(
631
- ({ filter }) => filter.chainId === chain.id,
632
- );
848
+ const eventCallbacks =
849
+ params.indexingBuild.eventCallbacks[
850
+ params.indexingBuild.chains.findIndex((c) => c.id === chain.id)
851
+ ]!;
633
852
 
634
853
  const chainEvents = params.events.filter(
635
- (event) => event.chainId === chain.id,
854
+ (event) => event.chain.id === chain.id,
636
855
  );
637
856
 
638
857
  if (chainEvents.length === 0) continue;
@@ -641,14 +860,19 @@ export async function refetchHistoricalEvents(params: {
641
860
  common: params.common,
642
861
  chain,
643
862
  childAddresses,
644
- sources,
863
+ eventCallbacks,
645
864
  events: chainEvents,
646
865
  syncStore: params.syncStore,
647
866
  });
648
867
 
649
868
  const endClock = startClock();
650
869
 
651
- const refetchedEvents = decodeEvents(params.common, sources, rawEvents);
870
+ const refetchedEvents = decodeEvents(
871
+ params.common,
872
+ chain,
873
+ eventCallbacks,
874
+ rawEvents,
875
+ );
652
876
 
653
877
  params.common.logger.trace({
654
878
  msg: "Decoded events",
@@ -667,7 +891,7 @@ export async function refetchHistoricalEvents(params: {
667
891
  let j = 0;
668
892
 
669
893
  while (i < params.events.length && j < refetchedEvents.length) {
670
- if (params.events[i]?.chainId === chain.id) {
894
+ if (params.events[i]?.chain.id === chain.id) {
671
895
  events[i] = refetchedEvents[j]!;
672
896
  i++;
673
897
  j++;
@@ -684,7 +908,7 @@ export async function refetchLocalEvents(params: {
684
908
  common: Common;
685
909
  chain: Chain;
686
910
  childAddresses: ChildAddresses;
687
- sources: Source[];
911
+ eventCallbacks: EventCallback[];
688
912
  events: Event[];
689
913
  syncStore: SyncStore;
690
914
  }): Promise<RawEvent[]> {
@@ -707,7 +931,7 @@ export async function refetchLocalEvents(params: {
707
931
  traces,
708
932
  cursor: queryCursor,
709
933
  } = await params.syncStore.getEventData({
710
- filters: params.sources.map(({ filter }) => filter),
934
+ filters: params.eventCallbacks.map(({ filter }) => filter),
711
935
  fromBlock: cursor,
712
936
  toBlock,
713
937
  chainId: params.chain.id,
@@ -716,7 +940,7 @@ export async function refetchLocalEvents(params: {
716
940
 
717
941
  const endClock = startClock();
718
942
  const rawEvents = buildEvents({
719
- sources: params.sources,
943
+ eventCallbacks: params.eventCallbacks,
720
944
  blocks,
721
945
  logs,
722
946
  transactions,
@@ -767,16 +991,21 @@ export async function* getLocalEventGenerator(params: {
767
991
  common: Common;
768
992
  chain: Chain;
769
993
  rpc: Rpc;
770
- sources: Source[];
994
+ eventCallbacks: EventCallback[];
771
995
  childAddresses: ChildAddresses;
772
996
  syncProgress: SyncProgress;
773
997
  cachedIntervals: CachedIntervals;
774
998
  from: string;
775
999
  to: string;
776
1000
  limit: number;
777
- syncStore: SyncStore;
1001
+ database: Database;
778
1002
  isCatchup: boolean;
779
1003
  }) {
1004
+ const syncStore = createSyncStore({
1005
+ common: params.common,
1006
+ qb: params.database.syncQB,
1007
+ });
1008
+
780
1009
  const fromBlock = Number(decodeCheckpoint(params.from).blockNumber);
781
1010
  const toBlock = Number(decodeCheckpoint(params.to).blockNumber);
782
1011
  let cursor = fromBlock;
@@ -797,8 +1026,8 @@ export async function* getLocalEventGenerator(params: {
797
1026
  transactionReceipts,
798
1027
  traces,
799
1028
  cursor: queryCursor,
800
- } = await params.syncStore.getEventData({
801
- filters: params.sources.map(({ filter }) => filter),
1029
+ } = await syncStore.getEventData({
1030
+ filters: params.eventCallbacks.map(({ filter }) => filter),
802
1031
  fromBlock: cursor,
803
1032
  toBlock: Math.min(syncCursor, toBlock),
804
1033
  chainId: params.chain.id,
@@ -807,7 +1036,7 @@ export async function* getLocalEventGenerator(params: {
807
1036
 
808
1037
  const endClock = startClock();
809
1038
  const events = buildEvents({
810
- sources: params.sources,
1039
+ eventCallbacks: params.eventCallbacks,
811
1040
  blocks,
812
1041
  logs,
813
1042
  transactions,
@@ -864,17 +1093,17 @@ export async function* getLocalSyncGenerator(params: {
864
1093
  common: Common;
865
1094
  chain: Chain;
866
1095
  rpc: Rpc;
867
- sources: Source[];
1096
+ eventCallbacks: EventCallback[];
868
1097
  syncProgress: SyncProgress;
869
1098
  childAddresses: ChildAddresses;
870
1099
  cachedIntervals: CachedIntervals;
871
- syncStore: SyncStore;
1100
+ database: Database;
872
1101
  isCatchup: boolean;
873
1102
  }) {
874
1103
  const backfillEndClock = startClock();
875
1104
  const label = { chain: params.chain.name };
876
1105
 
877
- let cursor = hexToNumber(params.syncProgress.start.number);
1106
+ let first = hexToNumber(params.syncProgress.start.number);
878
1107
  const last =
879
1108
  params.syncProgress.end === undefined
880
1109
  ? params.syncProgress.finalized
@@ -924,61 +1153,13 @@ export async function* getLocalSyncGenerator(params: {
924
1153
  hexToNumber(last!.number),
925
1154
  ] satisfies Interval;
926
1155
 
927
- const requiredIntervals = Array.from(
928
- params.cachedIntervals.entries(),
929
- ).flatMap(([filter, fragmentIntervals]) => {
930
- const filterIntervals: Interval[] = [
931
- [
932
- filter.fromBlock ?? 0,
933
- Math.min(filter.toBlock ?? Number.POSITIVE_INFINITY, totalInterval[1]),
934
- ],
935
- ];
936
-
937
- switch (filter.type) {
938
- case "log":
939
- if (isAddressFactory(filter.address)) {
940
- filterIntervals.push([
941
- filter.address.fromBlock ?? 0,
942
- Math.min(
943
- filter.address.toBlock ?? Number.POSITIVE_INFINITY,
944
- totalInterval[1],
945
- ),
946
- ]);
947
- }
948
- break;
949
- case "trace":
950
- case "transaction":
951
- case "transfer":
952
- if (isAddressFactory(filter.fromAddress)) {
953
- filterIntervals.push([
954
- filter.fromAddress.fromBlock ?? 0,
955
- Math.min(
956
- filter.fromAddress.toBlock ?? Number.POSITIVE_INFINITY,
957
- totalInterval[1],
958
- ),
959
- ]);
960
- }
961
-
962
- if (isAddressFactory(filter.toAddress)) {
963
- filterIntervals.push([
964
- filter.toAddress.fromBlock ?? 0,
965
- Math.min(
966
- filter.toAddress.toBlock ?? Number.POSITIVE_INFINITY,
967
- totalInterval[1],
968
- ),
969
- ]);
970
- }
971
- }
972
-
973
- return intervalDifference(
974
- intervalUnion(filterIntervals),
975
- intervalIntersectionMany(
976
- fragmentIntervals.map(({ intervals }) => intervals),
977
- ),
978
- );
1156
+ const requiredIntervals = getRequiredIntervals({
1157
+ filters: params.eventCallbacks.map(({ filter }) => filter),
1158
+ interval: totalInterval,
1159
+ cachedIntervals: params.cachedIntervals,
979
1160
  });
980
1161
 
981
- const required = intervalSum(intervalUnion(requiredIntervals));
1162
+ const required = intervalSum(requiredIntervals);
982
1163
  const total = totalInterval[1] - totalInterval[0] + 1;
983
1164
 
984
1165
  params.common.metrics.ponder_historical_total_blocks.set(label, total);
@@ -1025,7 +1206,7 @@ export async function* getLocalSyncGenerator(params: {
1025
1206
  });
1026
1207
  }
1027
1208
 
1028
- cursor = hexToNumber(params.syncProgress.current.number) + 1;
1209
+ first = hexToNumber(params.syncProgress.current.number) + 1;
1029
1210
  } else {
1030
1211
  params.common.logger.info({
1031
1212
  msg: "Started fetching backfill JSON-RPC data",
@@ -1037,115 +1218,212 @@ export async function* getLocalSyncGenerator(params: {
1037
1218
 
1038
1219
  const historicalSync = createHistoricalSync(params);
1039
1220
 
1040
- while (true) {
1041
- // Select a range of blocks to sync bounded by `finalizedBlock`.
1042
- // It is important for devEx that the interval is not too large, because
1043
- // time spent syncing ≈ time before indexing function feedback.
1044
-
1045
- const interval: Interval = [
1046
- Math.min(cursor, hexToNumber(last.number)),
1047
- Math.min(cursor + estimateRange, hexToNumber(last.number)),
1048
- ];
1221
+ const { callback: intervalCallback, generator: intervalGenerator } =
1222
+ createCallbackGenerator<{
1223
+ interval: Interval;
1224
+ promise: Promise<void>;
1225
+ }>();
1226
+
1227
+ intervalCallback({
1228
+ interval: [
1229
+ first,
1230
+ Math.min(first + estimateRange, hexToNumber(last.number)),
1231
+ ],
1232
+ promise: Promise.resolve(),
1233
+ });
1049
1234
 
1235
+ /**
1236
+ * @returns `true` if any data was inserted into the database.
1237
+ */
1238
+ async function syncInterval({
1239
+ interval,
1240
+ promise,
1241
+ }: { interval: Interval; promise: Promise<void> }): Promise<boolean> {
1050
1242
  const endClock = startClock();
1051
1243
 
1052
- const durationTimer = setTimeout(() => {
1053
- params.common.logger.warn({
1054
- msg: "Fetching backfill JSON-RPC data is taking longer than expected",
1055
- chain: params.chain.name,
1056
- chain_id: params.chain.id,
1057
- block_range: JSON.stringify(interval),
1058
- duration: endClock(),
1244
+ const isSyncComplete = interval[1] === hexToNumber(last.number);
1245
+ const {
1246
+ intervals: requiredIntervals,
1247
+ factoryIntervals: requiredFactoryIntervals,
1248
+ } = getRequiredIntervalsWithFilters({
1249
+ interval,
1250
+ filters: params.eventCallbacks.map(({ filter }) => filter),
1251
+ cachedIntervals: params.cachedIntervals,
1252
+ });
1253
+
1254
+ let closestToTipBlock: SyncBlock | undefined;
1255
+ if (requiredIntervals.length > 0 || requiredFactoryIntervals.length > 0) {
1256
+ const pwr = promiseWithResolvers<void>();
1257
+
1258
+ const durationTimer = setTimeout(
1259
+ () => {
1260
+ params.common.logger.warn({
1261
+ msg: "Fetching backfill JSON-RPC data is taking longer than expected",
1262
+ chain: params.chain.name,
1263
+ chain_id: params.chain.id,
1264
+ block_range: JSON.stringify(interval),
1265
+ duration: endClock(),
1266
+ });
1267
+ },
1268
+ params.common.options.command === "dev" ? 10_000 : 50_000,
1269
+ );
1270
+
1271
+ closestToTipBlock = await params.database.syncQB
1272
+ .transaction(async (tx) => {
1273
+ const syncStore = createSyncStore({ common: params.common, qb: tx });
1274
+ const logs = await historicalSync.syncBlockRangeData({
1275
+ interval,
1276
+ requiredIntervals,
1277
+ requiredFactoryIntervals,
1278
+ syncStore,
1279
+ });
1280
+
1281
+ // Wait for the previous interval to complete `syncBlockData`.
1282
+ await promise;
1283
+
1284
+ if (isSyncComplete === false) {
1285
+ // Queue the next interval
1286
+ intervalCallback({
1287
+ interval: [
1288
+ Math.min(interval[1] + 1, hexToNumber(last.number)),
1289
+ Math.min(
1290
+ interval[1] + 1 + estimateRange,
1291
+ hexToNumber(last.number),
1292
+ ),
1293
+ ],
1294
+ promise: pwr.promise,
1295
+ });
1296
+ }
1297
+
1298
+ const closestToTipBlock = await historicalSync.syncBlockData({
1299
+ interval,
1300
+ requiredIntervals,
1301
+ logs,
1302
+ syncStore,
1303
+ });
1304
+ if (params.chain.disableCache === false) {
1305
+ await syncStore.insertIntervals({
1306
+ intervals: requiredIntervals,
1307
+ factoryIntervals: requiredFactoryIntervals,
1308
+ chainId: params.chain.id,
1309
+ });
1310
+ }
1311
+
1312
+ return closestToTipBlock;
1313
+ })
1314
+ .catch((error) => {
1315
+ if (error instanceof ShutdownError) {
1316
+ throw error;
1317
+ }
1318
+
1319
+ params.common.logger.warn({
1320
+ msg: "Failed to fetch backfill JSON-RPC data",
1321
+ chain: params.chain.name,
1322
+ chain_id: params.chain.id,
1323
+ block_range: JSON.stringify(interval),
1324
+ duration: endClock(),
1325
+ error,
1326
+ });
1327
+ throw error;
1328
+ });
1329
+
1330
+ clearTimeout(durationTimer);
1331
+
1332
+ const duration = endClock();
1333
+
1334
+ // Use the duration and interval of the last call to `sync` to update estimate
1335
+ estimateRange = estimate({
1336
+ from: interval[0],
1337
+ to: interval[1],
1338
+ target: params.common.options.command === "dev" ? 2_000 : 10_000,
1339
+ result: duration,
1340
+ min: 25,
1341
+ max: 100_000,
1342
+ prev: estimateRange,
1343
+ maxIncrease: 1.5,
1059
1344
  });
1060
- }, 5_000);
1061
-
1062
- let synced: SyncBlock | undefined;
1063
- try {
1064
- synced = await historicalSync.sync(interval);
1065
- } catch (error) {
1066
- if (error instanceof ShutdownError) {
1067
- throw error;
1068
- }
1069
1345
 
1070
- params.common.logger.warn({
1071
- msg: "Failed to fetch backfill JSON-RPC data",
1346
+ params.common.logger.trace({
1347
+ msg: "Updated block range estimate for fetching backfill JSON-RPC data",
1072
1348
  chain: params.chain.name,
1073
1349
  chain_id: params.chain.id,
1074
- block_range: JSON.stringify(interval),
1075
- duration: endClock(),
1076
- error,
1350
+ range: estimateRange,
1077
1351
  });
1078
- throw error;
1079
- }
1080
-
1081
- clearTimeout(durationTimer);
1082
-
1083
- // Update cursor to record progress
1084
- cursor = interval[1] + 1;
1085
1352
 
1086
- // `synced` will be undefined if a cache hit occur in `historicalSync.sync()`.
1087
-
1088
- if (synced === undefined) {
1089
- // If the all known blocks are synced, then update `syncProgress.current`, else
1090
- // progress to the next iteration.
1091
- if (interval[1] === hexToNumber(last.number)) {
1092
- params.syncProgress.current = last;
1093
- } else {
1094
- continue;
1095
- }
1353
+ // Resolve promise so the next interval can continue.
1354
+ pwr.resolve();
1096
1355
  } else {
1097
- if (interval[1] === hexToNumber(last.number)) {
1098
- params.syncProgress.current = last;
1099
- } else {
1100
- params.syncProgress.current = synced;
1356
+ // Wait for the previous interval to complete `syncBlockData`.
1357
+ await promise;
1358
+
1359
+ if (isSyncComplete === false) {
1360
+ // Queue the next interval
1361
+ intervalCallback({
1362
+ interval: [
1363
+ Math.min(interval[1] + 1, hexToNumber(last.number)),
1364
+ Math.min(interval[1] + 1 + estimateRange, hexToNumber(last.number)),
1365
+ ],
1366
+ promise: Promise.resolve(),
1367
+ });
1101
1368
  }
1369
+ }
1102
1370
 
1103
- const duration = endClock();
1371
+ if (interval[1] === hexToNumber(last.number)) {
1372
+ params.syncProgress.current = last;
1373
+ }
1104
1374
 
1375
+ if (closestToTipBlock) {
1105
1376
  params.common.metrics.ponder_sync_block.set(
1106
1377
  label,
1107
- hexToNumber(params.syncProgress.current!.number),
1378
+ hexToNumber(closestToTipBlock.number),
1108
1379
  );
1109
1380
  params.common.metrics.ponder_sync_block_timestamp.set(
1110
1381
  label,
1111
- hexToNumber(params.syncProgress.current!.timestamp),
1112
- );
1113
- params.common.metrics.ponder_historical_completed_blocks.inc(
1114
- label,
1115
- interval[1] - interval[0] + 1,
1382
+ hexToNumber(closestToTipBlock.timestamp),
1116
1383
  );
1384
+ } else {
1385
+ params.common.metrics.ponder_sync_block.set(label, interval[1]);
1386
+ }
1117
1387
 
1118
- // Use the duration and interval of the last call to `sync` to update estimate
1119
- // 25 <= estimate(new) <= estimate(prev) * 2 <= 100_000
1120
- estimateRange = Math.min(
1121
- Math.max(
1122
- 25,
1123
- Math.round((1_000 * (interval[1] - interval[0])) / duration),
1124
- ),
1125
- estimateRange * 2,
1126
- 100_000,
1127
- );
1388
+ params.common.metrics.ponder_historical_completed_blocks.inc(
1389
+ label,
1390
+ interval[1] - interval[0] + 1,
1391
+ );
1128
1392
 
1129
- params.common.logger.trace({
1130
- msg: "Updated block range estimate for fetching backfill JSON-RPC data",
1131
- chain: params.chain.name,
1132
- chain_id: params.chain.id,
1133
- range: estimateRange,
1134
- });
1135
- }
1393
+ return requiredIntervals.length > 0;
1394
+ }
1136
1395
 
1137
- yield hexToNumber(params.syncProgress.current!.number);
1396
+ const { callback, generator } =
1397
+ createCallbackGenerator<IteratorResult<number>>();
1398
+
1399
+ (async () => {
1400
+ for await (const { interval, promise } of intervalGenerator) {
1401
+ // Note: this relies on the invariant that `syncInterval`
1402
+ // will always resolve promises in the order it was called.
1403
+ syncInterval({ interval, promise }).then((didInsertData) => {
1404
+ const isDone = interval[1] === hexToNumber(last.number);
1405
+ if (didInsertData || isDone) {
1406
+ callback({ value: interval[1], done: false });
1407
+ }
1138
1408
 
1139
- if (params.syncProgress.isEnd() || params.syncProgress.isFinalized()) {
1140
- params.common.logger.info({
1141
- msg: "Finished fetching backfill JSON-RPC data",
1142
- chain: params.chain.name,
1143
- chain_id: params.chain.id,
1144
- duration: backfillEndClock(),
1409
+ if (isDone) {
1410
+ callback({ value: undefined, done: true });
1411
+ }
1145
1412
  });
1146
- return;
1147
1413
  }
1414
+ })();
1415
+
1416
+ for await (const result of generator) {
1417
+ if (result.done) break;
1418
+ yield result.value;
1148
1419
  }
1420
+
1421
+ params.common.logger.info({
1422
+ msg: "Finished fetching backfill JSON-RPC data",
1423
+ chain: params.chain.name,
1424
+ chain_id: params.chain.id,
1425
+ duration: backfillEndClock(),
1426
+ });
1149
1427
  }
1150
1428
 
1151
1429
  /**
@@ -1202,7 +1480,7 @@ export async function* mergeAsyncGeneratorsWithEventOrder(
1202
1480
 
1203
1481
  mergedResults.push({
1204
1482
  events: left,
1205
- chainId: event.chainId,
1483
+ chainId: event.chain.id,
1206
1484
  checkpoint:
1207
1485
  right.length > 0 ? event.checkpoint : result.value.checkpoint,
1208
1486
  blockRange,