envio 3.0.0-alpha.2 → 3.0.0-alpha.21

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 (184) hide show
  1. package/README.md +164 -30
  2. package/bin.mjs +49 -0
  3. package/evm.schema.json +79 -169
  4. package/fuel.schema.json +50 -21
  5. package/index.d.ts +578 -1
  6. package/index.js +4 -0
  7. package/package.json +47 -31
  8. package/rescript.json +4 -1
  9. package/src/Batch.res +11 -8
  10. package/src/Batch.res.mjs +11 -9
  11. package/src/ChainFetcher.res +531 -0
  12. package/src/ChainFetcher.res.mjs +339 -0
  13. package/src/ChainManager.res +190 -0
  14. package/src/ChainManager.res.mjs +166 -0
  15. package/src/Change.res +3 -3
  16. package/src/Config.gen.ts +19 -0
  17. package/src/Config.res +725 -25
  18. package/src/Config.res.mjs +692 -26
  19. package/src/{Indexer.res → Ctx.res} +1 -1
  20. package/src/Ecosystem.res +9 -124
  21. package/src/Ecosystem.res.mjs +19 -160
  22. package/src/Env.res +33 -73
  23. package/src/Env.res.mjs +29 -85
  24. package/src/Envio.gen.ts +3 -1
  25. package/src/Envio.res +77 -9
  26. package/src/Envio.res.mjs +39 -1
  27. package/src/EventConfigBuilder.res +408 -0
  28. package/src/EventConfigBuilder.res.mjs +376 -0
  29. package/src/EventProcessing.res +469 -0
  30. package/src/EventProcessing.res.mjs +337 -0
  31. package/src/EvmTypes.gen.ts +6 -0
  32. package/src/EvmTypes.res +1 -0
  33. package/src/FetchState.res +1256 -639
  34. package/src/FetchState.res.mjs +1135 -612
  35. package/src/GlobalState.res +1224 -0
  36. package/src/GlobalState.res.mjs +1291 -0
  37. package/src/GlobalStateManager.res +68 -0
  38. package/src/GlobalStateManager.res.mjs +75 -0
  39. package/src/GlobalStateManager.resi +7 -0
  40. package/src/HandlerLoader.res +89 -0
  41. package/src/HandlerLoader.res.mjs +79 -0
  42. package/src/HandlerRegister.res +357 -0
  43. package/src/HandlerRegister.res.mjs +299 -0
  44. package/src/HandlerRegister.resi +30 -0
  45. package/src/Hasura.res +111 -175
  46. package/src/Hasura.res.mjs +88 -150
  47. package/src/InMemoryStore.res +1 -1
  48. package/src/InMemoryStore.res.mjs +3 -3
  49. package/src/InMemoryTable.res +1 -1
  50. package/src/InMemoryTable.res.mjs +1 -1
  51. package/src/Internal.gen.ts +6 -0
  52. package/src/Internal.res +265 -12
  53. package/src/Internal.res.mjs +115 -1
  54. package/src/LoadLayer.res +444 -0
  55. package/src/LoadLayer.res.mjs +296 -0
  56. package/src/LoadLayer.resi +32 -0
  57. package/src/LogSelection.res +33 -27
  58. package/src/LogSelection.res.mjs +6 -0
  59. package/src/Logging.res +21 -7
  60. package/src/Logging.res.mjs +16 -8
  61. package/src/Main.res +390 -0
  62. package/src/Main.res.mjs +341 -0
  63. package/src/Persistence.res +7 -21
  64. package/src/Persistence.res.mjs +3 -3
  65. package/src/PgStorage.gen.ts +10 -0
  66. package/src/PgStorage.res +116 -69
  67. package/src/PgStorage.res.d.mts +5 -0
  68. package/src/PgStorage.res.mjs +93 -50
  69. package/src/Prometheus.res +294 -224
  70. package/src/Prometheus.res.mjs +353 -340
  71. package/src/ReorgDetection.res +6 -10
  72. package/src/ReorgDetection.res.mjs +6 -6
  73. package/src/SafeCheckpointTracking.res +4 -4
  74. package/src/SafeCheckpointTracking.res.mjs +2 -2
  75. package/src/SimulateItems.res +353 -0
  76. package/src/SimulateItems.res.mjs +335 -0
  77. package/src/Sink.res +4 -2
  78. package/src/Sink.res.mjs +2 -1
  79. package/src/TableIndices.res +0 -1
  80. package/src/TestIndexer.res +913 -0
  81. package/src/TestIndexer.res.mjs +698 -0
  82. package/src/TestIndexerProxyStorage.res +205 -0
  83. package/src/TestIndexerProxyStorage.res.mjs +151 -0
  84. package/src/TopicFilter.res +1 -1
  85. package/src/Types.ts +1 -1
  86. package/src/UserContext.res +424 -0
  87. package/src/UserContext.res.mjs +279 -0
  88. package/src/Utils.res +97 -26
  89. package/src/Utils.res.mjs +91 -44
  90. package/src/bindings/BigInt.res +10 -0
  91. package/src/bindings/BigInt.res.mjs +15 -0
  92. package/src/bindings/ClickHouse.res +120 -23
  93. package/src/bindings/ClickHouse.res.mjs +118 -28
  94. package/src/bindings/DateFns.res +74 -0
  95. package/src/bindings/DateFns.res.mjs +22 -0
  96. package/src/bindings/EventSource.res +11 -2
  97. package/src/bindings/EventSource.res.mjs +8 -1
  98. package/src/bindings/Express.res +1 -0
  99. package/src/bindings/Hrtime.res +14 -1
  100. package/src/bindings/Hrtime.res.mjs +22 -2
  101. package/src/bindings/Hrtime.resi +4 -0
  102. package/src/bindings/Lodash.res +0 -1
  103. package/src/bindings/NodeJs.res +49 -3
  104. package/src/bindings/NodeJs.res.mjs +11 -3
  105. package/src/bindings/Pino.res +24 -10
  106. package/src/bindings/Pino.res.mjs +14 -8
  107. package/src/bindings/Postgres.gen.ts +8 -0
  108. package/src/bindings/Postgres.res +5 -1
  109. package/src/bindings/Postgres.res.d.mts +5 -0
  110. package/src/bindings/PromClient.res +0 -10
  111. package/src/bindings/PromClient.res.mjs +0 -3
  112. package/src/bindings/Vitest.res +144 -0
  113. package/src/bindings/Vitest.res.mjs +9 -0
  114. package/src/bindings/WebSocket.res +27 -0
  115. package/src/bindings/WebSocket.res.mjs +2 -0
  116. package/src/bindings/Yargs.res +8 -0
  117. package/src/bindings/Yargs.res.mjs +2 -0
  118. package/src/db/EntityHistory.res +7 -7
  119. package/src/db/EntityHistory.res.mjs +9 -9
  120. package/src/db/InternalTable.res +59 -111
  121. package/src/db/InternalTable.res.mjs +73 -104
  122. package/src/db/Table.res +27 -8
  123. package/src/db/Table.res.mjs +25 -14
  124. package/src/sources/Evm.res +84 -0
  125. package/src/sources/Evm.res.mjs +105 -0
  126. package/src/sources/EvmChain.res +94 -0
  127. package/src/sources/EvmChain.res.mjs +60 -0
  128. package/src/sources/Fuel.res +19 -34
  129. package/src/sources/Fuel.res.mjs +34 -16
  130. package/src/sources/FuelSDK.res +38 -0
  131. package/src/sources/FuelSDK.res.mjs +29 -0
  132. package/src/sources/HyperFuel.res +2 -2
  133. package/src/sources/HyperFuel.resi +1 -1
  134. package/src/sources/HyperFuelClient.res +2 -2
  135. package/src/sources/HyperFuelSource.res +35 -13
  136. package/src/sources/HyperFuelSource.res.mjs +26 -16
  137. package/src/sources/HyperSync.res +61 -60
  138. package/src/sources/HyperSync.res.mjs +53 -67
  139. package/src/sources/HyperSync.resi +6 -4
  140. package/src/sources/HyperSyncClient.res +29 -2
  141. package/src/sources/HyperSyncClient.res.mjs +9 -0
  142. package/src/sources/HyperSyncHeightStream.res +76 -118
  143. package/src/sources/HyperSyncHeightStream.res.mjs +68 -75
  144. package/src/sources/HyperSyncSource.res +122 -143
  145. package/src/sources/HyperSyncSource.res.mjs +106 -121
  146. package/src/sources/Rpc.res +86 -14
  147. package/src/sources/Rpc.res.mjs +101 -9
  148. package/src/sources/RpcSource.res +731 -364
  149. package/src/sources/RpcSource.res.mjs +845 -410
  150. package/src/sources/RpcWebSocketHeightStream.res +181 -0
  151. package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
  152. package/src/sources/SimulateSource.res +59 -0
  153. package/src/sources/SimulateSource.res.mjs +50 -0
  154. package/src/sources/Source.res +7 -5
  155. package/src/sources/SourceManager.res +358 -221
  156. package/src/sources/SourceManager.res.mjs +346 -171
  157. package/src/sources/SourceManager.resi +17 -6
  158. package/src/sources/Svm.res +81 -0
  159. package/src/sources/Svm.res.mjs +90 -0
  160. package/src/tui/Tui.res +247 -0
  161. package/src/tui/Tui.res.mjs +337 -0
  162. package/src/tui/bindings/Ink.res +371 -0
  163. package/src/tui/bindings/Ink.res.mjs +72 -0
  164. package/src/tui/bindings/Style.res +123 -0
  165. package/src/tui/bindings/Style.res.mjs +2 -0
  166. package/src/tui/components/BufferedProgressBar.res +40 -0
  167. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  168. package/src/tui/components/CustomHooks.res +122 -0
  169. package/src/tui/components/CustomHooks.res.mjs +179 -0
  170. package/src/tui/components/Messages.res +41 -0
  171. package/src/tui/components/Messages.res.mjs +75 -0
  172. package/src/tui/components/SyncETA.res +174 -0
  173. package/src/tui/components/SyncETA.res.mjs +263 -0
  174. package/src/tui/components/TuiData.res +47 -0
  175. package/src/tui/components/TuiData.res.mjs +34 -0
  176. package/svm.schema.json +112 -0
  177. package/bin.js +0 -48
  178. package/src/EventRegister.res +0 -241
  179. package/src/EventRegister.res.mjs +0 -240
  180. package/src/EventRegister.resi +0 -30
  181. package/src/bindings/Ethers.gen.ts +0 -14
  182. package/src/bindings/Ethers.res +0 -204
  183. package/src/bindings/Ethers.res.mjs +0 -130
  184. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
@@ -0,0 +1,469 @@
1
+ open Belt
2
+
3
+ let allChainsEventsProcessedToEndblock = (chainFetchers: ChainMap.t<ChainFetcher.t>) => {
4
+ chainFetchers
5
+ ->ChainMap.values
6
+ ->Array.every(cf => cf->ChainFetcher.hasProcessedToEndblock)
7
+ }
8
+
9
+ let computeChainsState = (chainFetchers: ChainMap.t<ChainFetcher.t>): Internal.chains => {
10
+ let chains = Js.Dict.empty()
11
+
12
+ chainFetchers
13
+ ->ChainMap.entries
14
+ ->Array.forEach(((chain, chainFetcher)) => {
15
+ let chainId = chain->ChainMap.Chain.toChainId->Int.toString
16
+ let isLive = chainFetcher->ChainFetcher.isReady
17
+
18
+ chains->Js.Dict.set(
19
+ chainId,
20
+ {
21
+ Internal.id: chain->ChainMap.Chain.toChainId,
22
+ isLive,
23
+ },
24
+ )
25
+ })
26
+
27
+ chains
28
+ }
29
+
30
+ let convertFieldsToJson = (fields: option<dict<unknown>>) => {
31
+ switch fields {
32
+ | None => %raw(`{}`)
33
+ | Some(fields) => {
34
+ let keys = fields->Js.Dict.keys
35
+ let new = Js.Dict.empty()
36
+ for i in 0 to keys->Js.Array2.length - 1 {
37
+ let key = keys->Js.Array2.unsafe_get(i)
38
+ let value = fields->Js.Dict.unsafeGet(key)
39
+ // Skip `undefined` values and convert bigint fields to string
40
+ // There are not fields with nested bigints, so this is safe
41
+ new->Js.Dict.set(
42
+ key,
43
+ Js.typeof(value) === "bigint"
44
+ ? value
45
+ ->(Utils.magic: unknown => bigint)
46
+ ->BigInt.toString
47
+ ->(Utils.magic: string => unknown)
48
+ : value,
49
+ )
50
+ }
51
+ new->(Utils.magic: dict<unknown> => Js.Json.t)
52
+ }
53
+ }
54
+ }
55
+
56
+ let addItemToRawEvents = (
57
+ eventItem: Internal.eventItem,
58
+ ~inMemoryStore: InMemoryStore.t,
59
+ ~config: Config.t,
60
+ ) => {
61
+ let {event, eventConfig, chain, blockNumber, timestamp: blockTimestamp} = eventItem
62
+ let {block, transaction, params, logIndex, srcAddress} = event
63
+ let chainId = chain->ChainMap.Chain.toChainId
64
+ let eventId = EventUtils.packEventIndex(~logIndex, ~blockNumber)
65
+ let blockFields =
66
+ block
67
+ ->(Utils.magic: Internal.eventBlock => option<dict<unknown>>)
68
+ ->convertFieldsToJson
69
+ let transactionFields =
70
+ transaction
71
+ ->(Utils.magic: Internal.eventTransaction => option<dict<unknown>>)
72
+ ->convertFieldsToJson
73
+
74
+ blockFields->config.ecosystem.cleanUpRawEventFieldsInPlace
75
+
76
+ // Serialize to unknown, because serializing to Js.Json.t fails for Bytes Fuel type, since it has unknown schema
77
+ let params =
78
+ params
79
+ ->S.reverseConvertOrThrow(eventConfig.paramsRawEventSchema)
80
+ ->(Utils.magic: unknown => Js.Json.t)
81
+ let params = if params === %raw(`null`) {
82
+ // Should probably make the params field nullable
83
+ // But this is currently needed to make events
84
+ // with empty params work
85
+ %raw(`"null"`)
86
+ } else {
87
+ params
88
+ }
89
+
90
+ let rawEvent: InternalTable.RawEvents.t = {
91
+ chainId,
92
+ eventId,
93
+ eventName: eventConfig.name,
94
+ contractName: eventConfig.contractName,
95
+ blockNumber,
96
+ logIndex,
97
+ srcAddress,
98
+ blockHash: block->config.ecosystem.getId,
99
+ blockTimestamp,
100
+ blockFields,
101
+ transactionFields,
102
+ params,
103
+ }
104
+
105
+ let eventIdStr = eventId->BigInt.toString
106
+
107
+ inMemoryStore.rawEvents->InMemoryTable.set({chainId, eventId: eventIdStr}, rawEvent)
108
+ }
109
+
110
+ exception ProcessingError({message: string, exn: exn, item: Internal.item})
111
+
112
+ let runEventHandlerOrThrow = async (
113
+ item: Internal.item,
114
+ ~checkpointId,
115
+ ~handler,
116
+ ~inMemoryStore,
117
+ ~loadManager,
118
+ ~persistence,
119
+ ~shouldSaveHistory,
120
+ ~chains: Internal.chains,
121
+ ~config: Config.t,
122
+ ) => {
123
+ let eventItem = item->Internal.castUnsafeEventItem
124
+
125
+ //Include the load in time before handler
126
+ let timeBeforeHandler = Hrtime.makeTimer()
127
+
128
+ try {
129
+ let contextParams: UserContext.contextParams = {
130
+ item,
131
+ checkpointId,
132
+ inMemoryStore,
133
+ loadManager,
134
+ persistence,
135
+ shouldSaveHistory,
136
+ isPreload: false,
137
+ chains,
138
+ config,
139
+ isResolved: false,
140
+ }
141
+ await handler(
142
+ (
143
+ {
144
+ event: eventItem.event,
145
+ context: UserContext.getHandlerContext(contextParams),
146
+ }: Internal.handlerArgs
147
+ ),
148
+ )
149
+ contextParams.isResolved = true
150
+ } catch {
151
+ | exn =>
152
+ raise(
153
+ ProcessingError({
154
+ message: "Unexpected error in the event handler. Please handle the error to keep the indexer running smoothly.",
155
+ item,
156
+ exn,
157
+ }),
158
+ )
159
+ }
160
+ let handlerDuration = timeBeforeHandler->Hrtime.timeSince->Hrtime.toSecondsFloat
161
+ Prometheus.ProcessingHandler.increment(
162
+ ~contract=eventItem.eventConfig.contractName,
163
+ ~event=eventItem.eventConfig.name,
164
+ ~duration=handlerDuration,
165
+ )
166
+ }
167
+
168
+ let runHandlerOrThrow = async (
169
+ item: Internal.item,
170
+ ~checkpointId,
171
+ ~inMemoryStore,
172
+ ~loadManager,
173
+ ~ctx: Ctx.t,
174
+ ~shouldSaveHistory,
175
+ ~chains: Internal.chains,
176
+ ) => {
177
+ switch item {
178
+ | Block({onBlockConfig: {handler}, blockNumber}) =>
179
+ try {
180
+ let contextParams: UserContext.contextParams = {
181
+ item,
182
+ inMemoryStore,
183
+ loadManager,
184
+ persistence: ctx.persistence,
185
+ shouldSaveHistory,
186
+ checkpointId,
187
+ isPreload: false,
188
+ chains,
189
+ config: ctx.config,
190
+ isResolved: false,
191
+ }
192
+ await handler(
193
+ Ecosystem.makeOnBlockArgs(
194
+ ~blockNumber,
195
+ ~ecosystem=ctx.config.ecosystem,
196
+ ~context=UserContext.getHandlerContext(contextParams),
197
+ ),
198
+ )
199
+ contextParams.isResolved = true
200
+ } catch {
201
+ | exn =>
202
+ raise(
203
+ ProcessingError({
204
+ message: "Unexpected error in the block handler. Please handle the error to keep the indexer running smoothly.",
205
+ item,
206
+ exn,
207
+ }),
208
+ )
209
+ }
210
+ | Event({eventConfig}) => {
211
+ switch eventConfig.handler {
212
+ | Some(handler) =>
213
+ await item->runEventHandlerOrThrow(
214
+ ~handler,
215
+ ~checkpointId,
216
+ ~inMemoryStore,
217
+ ~loadManager,
218
+ ~persistence=ctx.persistence,
219
+ ~shouldSaveHistory,
220
+ ~chains,
221
+ ~config=ctx.config,
222
+ )
223
+ | None => ()
224
+ }
225
+
226
+ if ctx.config.enableRawEvents {
227
+ item
228
+ ->Internal.castUnsafeEventItem
229
+ ->addItemToRawEvents(~inMemoryStore, ~config=ctx.config)
230
+ }
231
+ }
232
+ }
233
+ }
234
+
235
+ let preloadBatchOrThrow = async (
236
+ batch: Batch.t,
237
+ ~loadManager,
238
+ ~persistence,
239
+ ~config: Config.t,
240
+ ~inMemoryStore,
241
+ ~chains: Internal.chains,
242
+ ) => {
243
+ // On the first run of loaders, we don't care about the result,
244
+ // whether it's an error or a return type.
245
+ // We'll rerun the loader again right before the handler run,
246
+ // to avoid having a stale data returned from the loader.
247
+
248
+ let promises = []
249
+ let itemIdx = ref(0)
250
+
251
+ for checkpointIdx in 0 to batch.checkpointIds->Array.length - 1 {
252
+ let checkpointId = batch.checkpointIds->Js.Array2.unsafe_get(checkpointIdx)
253
+ let checkpointEventsProcessed =
254
+ batch.checkpointEventsProcessed->Js.Array2.unsafe_get(checkpointIdx)
255
+
256
+ for idx in 0 to checkpointEventsProcessed - 1 {
257
+ let item = batch.items->Js.Array2.unsafe_get(itemIdx.contents + idx)
258
+ switch item {
259
+ | Event({eventConfig: {handler, contractName, name: eventName}, event}) =>
260
+ switch handler {
261
+ | None => ()
262
+ | Some(handler) =>
263
+ try {
264
+ let timerRef = Prometheus.PreloadHandler.startOperation(
265
+ ~contract=contractName,
266
+ ~event=eventName,
267
+ )
268
+ promises->Array.push(
269
+ handler({
270
+ event,
271
+ context: UserContext.getHandlerContext({
272
+ item,
273
+ inMemoryStore,
274
+ loadManager,
275
+ persistence,
276
+ checkpointId,
277
+ isPreload: true,
278
+ shouldSaveHistory: false,
279
+ chains,
280
+ isResolved: false,
281
+ config,
282
+ }),
283
+ })
284
+ ->Promise.thenResolve(_ => {
285
+ timerRef->Prometheus.PreloadHandler.endOperation(
286
+ ~contract=contractName,
287
+ ~event=eventName,
288
+ )
289
+ })
290
+ ->Promise.silentCatch,
291
+ // Must have Promise.catch as well as normal catch,
292
+ // because if user throws an error before await in the handler,
293
+ // it won't create a rejected promise
294
+ )
295
+ } catch {
296
+ | _ => ()
297
+ }
298
+ }
299
+ | Block({onBlockConfig: {handler}, blockNumber}) =>
300
+ try {
301
+ promises->Array.push(
302
+ handler({
303
+ Ecosystem.makeOnBlockArgs(
304
+ ~blockNumber,
305
+ ~ecosystem=config.ecosystem,
306
+ ~context=UserContext.getHandlerContext({
307
+ item,
308
+ inMemoryStore,
309
+ loadManager,
310
+ persistence,
311
+ checkpointId,
312
+ isPreload: true,
313
+ shouldSaveHistory: false,
314
+ chains,
315
+ isResolved: false,
316
+ config,
317
+ }),
318
+ )
319
+ })->Promise.silentCatch,
320
+ )
321
+ } catch {
322
+ | _ => ()
323
+ }
324
+ }
325
+ }
326
+
327
+ itemIdx := itemIdx.contents + checkpointEventsProcessed
328
+ }
329
+
330
+ let _ = await Promise.all(promises)
331
+ }
332
+
333
+ let runBatchHandlersOrThrow = async (
334
+ batch: Batch.t,
335
+ ~inMemoryStore,
336
+ ~loadManager,
337
+ ~ctx,
338
+ ~shouldSaveHistory,
339
+ ~chains: Internal.chains,
340
+ ) => {
341
+ let itemIdx = ref(0)
342
+
343
+ for checkpointIdx in 0 to batch.checkpointIds->Array.length - 1 {
344
+ let checkpointId = batch.checkpointIds->Js.Array2.unsafe_get(checkpointIdx)
345
+ let checkpointEventsProcessed =
346
+ batch.checkpointEventsProcessed->Js.Array2.unsafe_get(checkpointIdx)
347
+
348
+ for idx in 0 to checkpointEventsProcessed - 1 {
349
+ let item = batch.items->Js.Array2.unsafe_get(itemIdx.contents + idx)
350
+
351
+ await runHandlerOrThrow(
352
+ item,
353
+ ~checkpointId,
354
+ ~inMemoryStore,
355
+ ~loadManager,
356
+ ~ctx,
357
+ ~shouldSaveHistory,
358
+ ~chains,
359
+ )
360
+ }
361
+ itemIdx := itemIdx.contents + checkpointEventsProcessed
362
+ }
363
+ }
364
+
365
+ let registerProcessEventBatchMetrics = (
366
+ ~logger,
367
+ ~loadDuration,
368
+ ~handlerDuration,
369
+ ~dbWriteDuration,
370
+ ) => {
371
+ logger->Logging.childTrace({
372
+ "msg": "Finished processing batch",
373
+ "loader_time_elapsed": loadDuration,
374
+ "handlers_time_elapsed": handlerDuration,
375
+ "write_time_elapsed": dbWriteDuration,
376
+ })
377
+
378
+ Prometheus.ProcessingBatch.registerMetrics(~loadDuration, ~handlerDuration, ~dbWriteDuration)
379
+ }
380
+
381
+ type logPartitionInfo = {
382
+ batchSize: int,
383
+ firstItemTimestamp: option<int>,
384
+ firstItemBlockNumber?: int,
385
+ lastItemBlockNumber?: int,
386
+ }
387
+
388
+ let processEventBatch = async (
389
+ ~batch: Batch.t,
390
+ ~inMemoryStore: InMemoryStore.t,
391
+ ~isInReorgThreshold,
392
+ ~loadManager,
393
+ ~ctx: Ctx.t,
394
+ ~chainFetchers: ChainMap.t<ChainFetcher.t>,
395
+ ) => {
396
+ let totalBatchSize = batch.totalBatchSize
397
+ // Compute chains state for this batch
398
+ let chains: Internal.chains = chainFetchers->computeChainsState
399
+
400
+ let logger = Logging.getLogger()
401
+ logger->Logging.childTrace({
402
+ "msg": "Started processing batch",
403
+ "totalBatchSize": totalBatchSize,
404
+ "chains": batch.progressedChainsById->Utils.Dict.mapValues(chainAfterBatch => {
405
+ {
406
+ "batchSize": chainAfterBatch.batchSize,
407
+ "progress": chainAfterBatch.progressBlockNumber,
408
+ }
409
+ }),
410
+ })
411
+
412
+ try {
413
+ let timeRef = Hrtime.makeTimer()
414
+
415
+ if batch.items->Utils.Array.notEmpty {
416
+ await batch->preloadBatchOrThrow(
417
+ ~loadManager,
418
+ ~persistence=ctx.persistence,
419
+ ~inMemoryStore,
420
+ ~chains,
421
+ ~config=ctx.config,
422
+ )
423
+ }
424
+
425
+ let elapsedTimeAfterLoaders = timeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
426
+
427
+ if batch.items->Utils.Array.notEmpty {
428
+ await batch->runBatchHandlersOrThrow(
429
+ ~inMemoryStore,
430
+ ~loadManager,
431
+ ~ctx,
432
+ ~shouldSaveHistory=ctx.config->Config.shouldSaveHistory(~isInReorgThreshold),
433
+ ~chains,
434
+ )
435
+ }
436
+
437
+ let elapsedTimeAfterProcessing = timeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
438
+
439
+ try {
440
+ await ctx.persistence->Persistence.writeBatch(
441
+ ~batch,
442
+ ~config=ctx.config,
443
+ ~inMemoryStore,
444
+ ~isInReorgThreshold,
445
+ )
446
+
447
+ let elapsedTimeAfterDbWrite = timeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
448
+ let loaderDuration = elapsedTimeAfterLoaders
449
+ let handlerDuration = elapsedTimeAfterProcessing -. loaderDuration
450
+ let dbWriteDuration = elapsedTimeAfterDbWrite -. elapsedTimeAfterProcessing
451
+ registerProcessEventBatchMetrics(
452
+ ~logger,
453
+ ~loadDuration=loaderDuration,
454
+ ~handlerDuration,
455
+ ~dbWriteDuration,
456
+ )
457
+ Ok()
458
+ } catch {
459
+ | Persistence.StorageError({message, reason}) =>
460
+ reason->ErrorHandling.make(~msg=message, ~logger)->Error
461
+ | exn => exn->ErrorHandling.make(~msg="Failed writing batch to database", ~logger)->Error
462
+ }
463
+ } catch {
464
+ | ProcessingError({message, exn, item}) =>
465
+ exn
466
+ ->ErrorHandling.make(~msg=message, ~logger=item->Logging.getItemLogger)
467
+ ->Error
468
+ }
469
+ }