envio 3.3.0-alpha.1 → 3.3.0-alpha.11

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 (143) hide show
  1. package/evm.schema.json +10 -0
  2. package/index.d.ts +45 -25
  3. package/licenses/CLA.md +35 -0
  4. package/licenses/EULA.md +67 -0
  5. package/licenses/LICENSE.md +45 -0
  6. package/licenses/README.md +35 -0
  7. package/package.json +10 -9
  8. package/src/Address.res +5 -2
  9. package/src/Address.res.mjs +3 -1
  10. package/src/Api.res +1 -1
  11. package/src/Api.res.mjs +1 -1
  12. package/src/Batch.res +0 -6
  13. package/src/Batch.res.mjs +1 -12
  14. package/src/BatchProcessing.res +7 -12
  15. package/src/BatchProcessing.res.mjs +8 -7
  16. package/src/Bin.res +3 -0
  17. package/src/Bin.res.mjs +4 -0
  18. package/src/ChainFetching.res +53 -16
  19. package/src/ChainFetching.res.mjs +37 -19
  20. package/src/ChainMetadata.res +1 -11
  21. package/src/ChainMetadata.res.mjs +1 -10
  22. package/src/ChainState.res +630 -161
  23. package/src/ChainState.res.mjs +438 -101
  24. package/src/ChainState.resi +77 -4
  25. package/src/Config.res +70 -38
  26. package/src/Config.res.mjs +52 -12
  27. package/src/ContractRegisterContext.res +2 -12
  28. package/src/ContractRegisterContext.res.mjs +3 -5
  29. package/src/Core.res +34 -3
  30. package/src/Core.res.mjs +12 -0
  31. package/src/CrossChainState.res +130 -89
  32. package/src/CrossChainState.res.mjs +66 -61
  33. package/src/CrossChainState.resi +1 -1
  34. package/src/Ecosystem.res +5 -6
  35. package/src/Ecosystem.res.mjs +3 -3
  36. package/src/Envio.res +17 -11
  37. package/src/EnvioGlobal.res +53 -0
  38. package/src/EnvioGlobal.res.mjs +31 -0
  39. package/src/EventConfigBuilder.res +191 -127
  40. package/src/EventConfigBuilder.res.mjs +116 -66
  41. package/src/EventProcessing.res +77 -28
  42. package/src/EventProcessing.res.mjs +56 -29
  43. package/src/ExitOnCaughtUp.res +10 -2
  44. package/src/ExitOnCaughtUp.res.mjs +10 -1
  45. package/src/FetchState.res +684 -415
  46. package/src/FetchState.res.mjs +505 -486
  47. package/src/HandlerLoader.res +8 -104
  48. package/src/HandlerLoader.res.mjs +2 -81
  49. package/src/HandlerRegister.res +520 -144
  50. package/src/HandlerRegister.res.mjs +286 -133
  51. package/src/HandlerRegister.resi +24 -8
  52. package/src/IndexerState.res +10 -3
  53. package/src/IndexerState.res.mjs +11 -4
  54. package/src/IndexerState.resi +2 -1
  55. package/src/IndexingAddresses.res +108 -0
  56. package/src/IndexingAddresses.res.mjs +101 -0
  57. package/src/IndexingAddresses.resi +34 -0
  58. package/src/Internal.res +166 -48
  59. package/src/Internal.res.mjs +30 -2
  60. package/src/LoadLayer.res +5 -5
  61. package/src/LoadLayer.res.mjs +6 -6
  62. package/src/LogSelection.res +92 -217
  63. package/src/LogSelection.res.mjs +95 -184
  64. package/src/Main.res +71 -236
  65. package/src/Main.res.mjs +60 -145
  66. package/src/Metrics.res +74 -0
  67. package/src/Metrics.res.mjs +75 -0
  68. package/src/PgStorage.res +4 -4
  69. package/src/PgStorage.res.mjs +5 -5
  70. package/src/Prometheus.res +10 -63
  71. package/src/Prometheus.res.mjs +124 -171
  72. package/src/PruneStaleHistory.res +2 -2
  73. package/src/PruneStaleHistory.res.mjs +3 -3
  74. package/src/RawEvent.res +7 -2
  75. package/src/RawEvent.res.mjs +4 -4
  76. package/src/Rollback.res +3 -3
  77. package/src/Rollback.res.mjs +4 -4
  78. package/src/RollbackCommit.res +4 -1
  79. package/src/RollbackCommit.res.mjs +3 -2
  80. package/src/SimulateDeadInputTracker.res +85 -0
  81. package/src/SimulateDeadInputTracker.res.mjs +73 -0
  82. package/src/SimulateDeadInputTracker.resi +12 -0
  83. package/src/SimulateItems.res +128 -28
  84. package/src/SimulateItems.res.mjs +82 -40
  85. package/src/TestIndexer.res +55 -41
  86. package/src/TestIndexer.res.mjs +39 -32
  87. package/src/TopicFilter.res +1 -25
  88. package/src/TopicFilter.res.mjs +0 -74
  89. package/src/bindings/Performance.res +7 -0
  90. package/src/bindings/Performance.res.mjs +21 -0
  91. package/src/bindings/Performance.resi +7 -0
  92. package/src/bindings/Viem.res +0 -46
  93. package/src/bindings/Viem.res.mjs +1 -43
  94. package/src/sources/BlockStore.res +46 -0
  95. package/src/sources/BlockStore.res.mjs +24 -0
  96. package/src/sources/EventRouter.res +31 -49
  97. package/src/sources/EventRouter.res.mjs +12 -25
  98. package/src/sources/Evm.res +83 -72
  99. package/src/sources/Evm.res.mjs +53 -69
  100. package/src/sources/EvmChain.res +7 -34
  101. package/src/sources/EvmChain.res.mjs +6 -27
  102. package/src/sources/EvmRpcClient.res +71 -5
  103. package/src/sources/EvmRpcClient.res.mjs +13 -4
  104. package/src/sources/FieldMask.res +39 -0
  105. package/src/sources/FieldMask.res.mjs +42 -0
  106. package/src/sources/Fuel.res +9 -6
  107. package/src/sources/Fuel.res.mjs +5 -10
  108. package/src/sources/HyperFuelSource.res +46 -50
  109. package/src/sources/HyperFuelSource.res.mjs +64 -54
  110. package/src/sources/HyperSync.res +45 -42
  111. package/src/sources/HyperSync.res.mjs +68 -60
  112. package/src/sources/HyperSync.resi +14 -4
  113. package/src/sources/HyperSyncClient.res +107 -119
  114. package/src/sources/HyperSyncClient.res.mjs +36 -31
  115. package/src/sources/HyperSyncHeightStream.res +1 -8
  116. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  117. package/src/sources/HyperSyncSource.res +60 -254
  118. package/src/sources/HyperSyncSource.res.mjs +57 -180
  119. package/src/sources/Rpc.res +15 -79
  120. package/src/sources/Rpc.res.mjs +25 -101
  121. package/src/sources/RpcSource.res +221 -514
  122. package/src/sources/RpcSource.res.mjs +216 -411
  123. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  124. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  125. package/src/sources/SimulateSource.res +44 -20
  126. package/src/sources/SimulateSource.res.mjs +41 -14
  127. package/src/sources/Source.res +34 -6
  128. package/src/sources/SourceManager.res +77 -19
  129. package/src/sources/SourceManager.res.mjs +63 -21
  130. package/src/sources/SourceManager.resi +10 -0
  131. package/src/sources/Svm.res +31 -16
  132. package/src/sources/Svm.res.mjs +36 -13
  133. package/src/sources/SvmHyperSyncClient.res +5 -32
  134. package/src/sources/SvmHyperSyncSource.res +159 -134
  135. package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
  136. package/src/sources/TransactionStore.res +49 -0
  137. package/src/sources/TransactionStore.res.mjs +30 -0
  138. package/src/tui/Tui.res +13 -16
  139. package/src/tui/Tui.res.mjs +12 -14
  140. package/svm.schema.json +49 -37
  141. package/src/bindings/Hrtime.res +0 -58
  142. package/src/bindings/Hrtime.res.mjs +0 -90
  143. package/src/bindings/Hrtime.resi +0 -30
@@ -1,10 +1,12 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Evm from "./sources/Evm.res.mjs";
4
+ import * as Svm from "./sources/Svm.res.mjs";
5
+ import * as Core from "./Core.res.mjs";
3
6
  import * as Utils from "./Utils.res.mjs";
4
7
  import * as Address from "./Address.res.mjs";
5
8
  import * as FuelSDK from "./sources/FuelSDK.res.mjs";
6
9
  import * as Internal from "./Internal.res.mjs";
7
- import * as TopicFilter from "./TopicFilter.res.mjs";
8
10
  import * as LogSelection from "./LogSelection.res.mjs";
9
11
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
10
12
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
@@ -206,34 +208,24 @@ function buildSimulateParamsSchema(params) {
206
208
  }
207
209
 
208
210
  function getTopicEncoder(abiType) {
209
- if (abiType.endsWith("]") || abiType.startsWith("(")) {
210
- return TopicFilter.castToHexUnsafe;
211
- }
212
- switch (abiType) {
213
- case "address" :
214
- return TopicFilter.fromAddress;
215
- case "bool" :
216
- return TopicFilter.fromBool;
217
- case "bytes" :
218
- return TopicFilter.fromDynamicBytes;
219
- case "string" :
220
- return TopicFilter.fromDynamicString;
221
- default:
222
- if (abiType.startsWith("uint")) {
223
- return TopicFilter.fromBigInt;
224
- } else if (abiType.startsWith("int")) {
225
- return TopicFilter.fromSignedBigInt;
226
- } else if (abiType.startsWith("bytes")) {
227
- return TopicFilter.castToHexUnsafe;
228
- } else {
229
- return Stdlib_JsError.throwWithMessage(`Unsupported topic filter ABI type: ` + abiType);
230
- }
231
- }
211
+ return value => Core.getAddon().encodeIndexedTopic(abiType, value);
232
212
  }
233
213
 
234
214
  function buildTopicGetter(p) {
235
215
  let encoder = getTopicEncoder(p.abiType);
236
- return eventFilter => Stdlib_Option.mapOr(eventFilter[p.name], [], topicFilters => normalizeOrThrow(topicFilters).map(encoder));
216
+ let isTuple = p.abiType.startsWith("(");
217
+ return eventFilter => Stdlib_Option.mapOr(eventFilter[p.name], [], topicFilters => {
218
+ if (!isTuple) {
219
+ return normalizeOrThrow(topicFilters).map(encoder);
220
+ }
221
+ let encoded;
222
+ try {
223
+ encoded = encoder(topicFilters);
224
+ } catch (exn) {
225
+ return normalizeOrThrow(topicFilters).map(encoder);
226
+ }
227
+ return [encoded];
228
+ });
237
229
  }
238
230
 
239
231
  let alwaysIncludedBlockFields = [
@@ -255,20 +247,30 @@ let compileAddressFilter = (function (body) {
255
247
  return new Function("event", "blockNumber", "indexingAddresses", body);
256
248
  });
257
249
 
258
- function buildAddressFilterBody(groups) {
259
- if (groups.length === 0) {
260
- return;
250
+ function buildAddressFilterBody(groups, isWildcard, srcAddressExprOpt) {
251
+ let srcAddressExpr = srcAddressExprOpt !== undefined ? srcAddressExprOpt : "event.srcAddress";
252
+ let paramLeaf = name => `(ic = indexingAddresses[p[` + JSON.stringify(name) + `]]) !== undefined && ic.effectiveStartBlock <= blockNumber`;
253
+ let paramDnf = groups.length !== 0 ? groups.map(group => "(" + group.map(paramLeaf).join(" && ") + ")").join(" || ") : undefined;
254
+ let srcLeaf = `(ic = indexingAddresses[` + srcAddressExpr + `]) !== undefined && ic.effectiveStartBlock <= blockNumber`;
255
+ if (isWildcard) {
256
+ if (paramDnf !== undefined) {
257
+ return "var p = event.params, ic; return " + paramDnf + ";";
258
+ } else {
259
+ return;
260
+ }
261
+ } else if (paramDnf !== undefined) {
262
+ return "var p = event.params, ic; return " + srcLeaf + " && (" + paramDnf + ");";
263
+ } else {
264
+ return "var ic; return " + srcLeaf + ";";
261
265
  }
262
- let leaf = name => `(ic = indexingAddresses[p[` + JSON.stringify(name) + `]]) !== undefined && ic.effectiveStartBlock <= blockNumber`;
263
- let groupExprs = groups.map(group => "(" + group.map(leaf).join(" && ") + ")");
264
- return "var p = event.params, ic; return " + groupExprs.join(" || ") + ";";
265
266
  }
266
267
 
267
- function buildAddressFilter(groups) {
268
- return Stdlib_Option.map(buildAddressFilterBody(groups), compileAddressFilter);
268
+ function buildAddressFilter(groups, isWildcard, srcAddressExprOpt) {
269
+ let srcAddressExpr = srcAddressExprOpt !== undefined ? srcAddressExprOpt : "event.srcAddress";
270
+ return Stdlib_Option.map(buildAddressFilterBody(groups, isWildcard, srcAddressExpr), compileAddressFilter);
269
271
  }
270
272
 
271
- function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcard, handler, contractRegister, eventFilters, probeChainId, onEventBlockFilterSchema, blockFields, transactionFields, startBlock, globalBlockFieldsSetOpt, globalTransactionFieldsSetOpt) {
273
+ function buildEvmEventConfig(contractName, eventName, sighash, params, blockFields, transactionFields, globalBlockFieldsSetOpt, globalTransactionFieldsSetOpt) {
272
274
  let globalBlockFieldsSet = globalBlockFieldsSetOpt !== undefined ? Primitive_option.valFromOption(globalBlockFieldsSetOpt) : new Set();
273
275
  let globalTransactionFieldsSet = globalTransactionFieldsSetOpt !== undefined ? Primitive_option.valFromOption(globalTransactionFieldsSetOpt) : new Set();
274
276
  let topicCount = Stdlib_Array.reduce(params, 1, (acc, p) => {
@@ -278,57 +280,76 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcar
278
280
  return acc;
279
281
  }
280
282
  });
281
- let indexedParams = params.filter(p => p.indexed);
282
- let match = LogSelection.parseEventFiltersOrThrow(eventFilters, sighash, indexedParams.map(p => p.name), contractName, probeChainId, onEventBlockFilterSchema, Stdlib_Option.map(indexedParams[0], buildTopicGetter), Stdlib_Option.map(indexedParams[1], buildTopicGetter), Stdlib_Option.map(indexedParams[2], buildTopicGetter));
283
- let whereStartBlock = match.startBlock;
284
- let filterByAddresses = match.filterByAddresses;
285
- let resolvedStartBlock = whereStartBlock !== undefined ? whereStartBlock : startBlock;
286
- let match$1 = resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet);
283
+ let match = resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet);
284
+ let selectedTransactionFields = match[1];
285
+ let selectedBlockFields = match[0];
287
286
  return {
288
287
  id: sighash + "_" + topicCount.toString(),
289
288
  name: eventName,
290
289
  contractName: contractName,
291
- isWildcard: isWildcard,
292
- filterByAddresses: filterByAddresses,
293
- dependsOnAddresses: !isWildcard || filterByAddresses,
294
- clientAddressFilter: Stdlib_Option.map(buildAddressFilterBody(match.addressFilterParamGroups), compileAddressFilter),
295
- handler: handler,
296
- contractRegister: contractRegister,
297
290
  paramsRawEventSchema: buildParamsSchema(params),
298
291
  simulateParamsSchema: buildSimulateParamsSchema(params),
299
- startBlock: resolvedStartBlock,
300
- getEventFiltersOrThrow: match.getEventFiltersOrThrow,
301
- selectedBlockFields: match$1[0],
302
- selectedTransactionFields: match$1[1],
292
+ selectedTransactionFields: selectedTransactionFields,
293
+ transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
294
+ blockFieldMask: Evm.eventBlockFieldMask(selectedBlockFields),
295
+ selectedBlockFields: selectedBlockFields,
303
296
  sighash: sighash,
304
297
  topicCount: topicCount,
305
298
  paramsMetadata: params
306
299
  };
307
300
  }
308
301
 
309
- function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, discriminatorByteLen, includeTransaction, includeLogs, includeTokenBalances, accountFilters, isInner, isWildcard, handler, contractRegister, accountsOpt, argsOpt, definedTypesOpt, startBlock) {
302
+ function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, chainId, onEventBlockFilterSchema, startBlock) {
303
+ let indexedParams = eventConfig.paramsMetadata.filter(p => p.indexed);
304
+ let match = LogSelection.parseWhereOrThrow(where, eventConfig.sighash, indexedParams.map(p => p.name), eventConfig.contractName, chainId, onEventBlockFilterSchema, Stdlib_Option.map(indexedParams[0], buildTopicGetter), Stdlib_Option.map(indexedParams[1], buildTopicGetter), Stdlib_Option.map(indexedParams[2], buildTopicGetter));
305
+ let filterByAddresses = match.filterByAddresses;
306
+ let resolvedWhere = match.resolvedWhere;
307
+ let sb = resolvedWhere.startBlock;
308
+ let resolvedStartBlock = sb !== undefined ? sb : startBlock;
309
+ return {
310
+ index: -1,
311
+ eventConfig: eventConfig,
312
+ handler: handler,
313
+ contractRegister: contractRegister,
314
+ isWildcard: isWildcard,
315
+ filterByAddresses: filterByAddresses,
316
+ dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, filterByAddresses),
317
+ clientAddressFilter: buildAddressFilter(match.addressFilterParamGroups, isWildcard, undefined),
318
+ startBlock: resolvedStartBlock,
319
+ resolvedWhere: resolvedWhere
320
+ };
321
+ }
322
+
323
+ let alwaysIncludedSvmBlockFields = [
324
+ "slot",
325
+ "time",
326
+ "hash"
327
+ ];
328
+
329
+ function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, discriminatorByteLen, includeLogs, transactionFieldsOpt, blockFieldsOpt, accountFilters, isInner, accountsOpt, argsOpt, definedTypesOpt) {
330
+ let transactionFields = transactionFieldsOpt !== undefined ? transactionFieldsOpt : [];
331
+ let blockFields = blockFieldsOpt !== undefined ? blockFieldsOpt : [];
310
332
  let accounts = accountsOpt !== undefined ? accountsOpt : [];
311
333
  let args = argsOpt !== undefined ? argsOpt : null;
312
334
  let definedTypes = definedTypesOpt !== undefined ? definedTypesOpt : null;
313
335
  let paramsSchema = Utils.Schema.coerceToJsonPgType(S$RescriptSchema.json(false));
336
+ let selectedTransactionFields = new Set(transactionFields);
337
+ let selectedBlockFields = new Set(alwaysIncludedSvmBlockFields.concat(blockFields));
338
+ let blockFieldMask = Svm.eventBlockFieldMask(selectedBlockFields);
314
339
  return {
315
340
  id: discriminator !== undefined ? discriminator : "none",
316
341
  name: instructionName,
317
342
  contractName: contractName,
318
- isWildcard: isWildcard,
319
- filterByAddresses: false,
320
- dependsOnAddresses: !isWildcard,
321
- handler: handler,
322
- contractRegister: contractRegister,
323
343
  paramsRawEventSchema: paramsSchema,
324
344
  simulateParamsSchema: paramsSchema,
325
- startBlock: startBlock,
345
+ selectedTransactionFields: selectedTransactionFields,
346
+ transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
347
+ blockFieldMask: blockFieldMask,
348
+ selectedBlockFields: selectedBlockFields,
326
349
  programId: programId,
327
350
  discriminator: discriminator,
328
351
  discriminatorByteLen: discriminatorByteLen,
329
- includeTransaction: includeTransaction,
330
352
  includeLogs: includeLogs,
331
- includeTokenBalances: includeTokenBalances,
332
353
  accountFilters: accountFilters,
333
354
  isInner: isInner,
334
355
  accounts: accounts,
@@ -337,7 +358,21 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
337
358
  };
338
359
  }
339
360
 
340
- function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi, isWildcard, handler, contractRegister, startBlock) {
361
+ function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
362
+ return {
363
+ index: -1,
364
+ eventConfig: eventConfig,
365
+ handler: handler,
366
+ contractRegister: contractRegister,
367
+ isWildcard: isWildcard,
368
+ filterByAddresses: false,
369
+ dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
370
+ clientAddressFilter: buildAddressFilter([], isWildcard, "event.programId"),
371
+ startBlock: startBlock
372
+ };
373
+ }
374
+
375
+ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
341
376
  let fuelKind;
342
377
  switch (kind) {
343
378
  case "burn" :
@@ -384,18 +419,29 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi, is
384
419
  id: tmp,
385
420
  name: eventName,
386
421
  contractName: contractName,
387
- isWildcard: isWildcard,
388
- filterByAddresses: false,
389
- dependsOnAddresses: !isWildcard,
390
- handler: handler,
391
- contractRegister: contractRegister,
392
422
  paramsRawEventSchema: paramsSchema,
393
423
  simulateParamsSchema: paramsSchema,
394
- startBlock: startBlock,
424
+ selectedTransactionFields: new Set(),
425
+ transactionFieldMask: 0,
426
+ blockFieldMask: 0,
395
427
  kind: fuelKind
396
428
  };
397
429
  }
398
430
 
431
+ function buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
432
+ return {
433
+ index: -1,
434
+ eventConfig: eventConfig,
435
+ handler: handler,
436
+ contractRegister: contractRegister,
437
+ isWildcard: isWildcard,
438
+ filterByAddresses: false,
439
+ dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
440
+ clientAddressFilter: buildAddressFilter([], isWildcard, undefined),
441
+ startBlock: startBlock
442
+ };
443
+ }
444
+
399
445
  export {
400
446
  paramMetaSchema,
401
447
  normalizeOrThrow,
@@ -415,7 +461,11 @@ export {
415
461
  buildAddressFilterBody,
416
462
  buildAddressFilter,
417
463
  buildEvmEventConfig,
464
+ buildEvmOnEventRegistration,
465
+ alwaysIncludedSvmBlockFields,
418
466
  buildSvmInstructionEventConfig,
467
+ buildSvmOnEventRegistration,
419
468
  buildFuelEventConfig,
469
+ buildFuelOnEventRegistration,
420
470
  }
421
471
  /* paramMetaSchema Not a pure module */
@@ -39,7 +39,7 @@ let runEventHandlerOrThrow = async (
39
39
  let eventItem = item->Internal.castUnsafeEventItem
40
40
 
41
41
  //Include the load in time before handler
42
- let timeBeforeHandler = Hrtime.makeTimer()
42
+ let timeBeforeHandler = Performance.now()
43
43
 
44
44
  try {
45
45
  let contextParams: UserContext.contextParams = {
@@ -72,10 +72,11 @@ let runEventHandlerOrThrow = async (
72
72
  }),
73
73
  )
74
74
  }
75
- let handlerDuration = timeBeforeHandler->Hrtime.timeSince->Hrtime.toSecondsFloat
75
+ let handlerDuration = timeBeforeHandler->Performance.secondsSince
76
+ let eventConfig = eventItem.onEventRegistration.eventConfig
76
77
  Prometheus.ProcessingHandler.increment(
77
- ~contract=eventItem.eventConfig.contractName,
78
- ~event=eventItem.eventConfig.name,
78
+ ~contract=eventConfig.contractName,
79
+ ~event=eventConfig.name,
79
80
  ~duration=handlerDuration,
80
81
  )
81
82
  }
@@ -90,7 +91,7 @@ let runHandlerOrThrow = async (
90
91
  ~chains: Internal.chains,
91
92
  ) => {
92
93
  switch item {
93
- | Block({onBlockConfig: {handler}, blockNumber}) =>
94
+ | Block({onBlockRegistration: {handler}, blockNumber}) =>
94
95
  try {
95
96
  let contextParams: UserContext.contextParams = {
96
97
  item,
@@ -121,8 +122,8 @@ let runHandlerOrThrow = async (
121
122
  }),
122
123
  )
123
124
  }
124
- | Event({eventConfig}) =>
125
- switch eventConfig.handler {
125
+ | Event(_) =>
126
+ switch (item->Internal.castUnsafeEventItem).onEventRegistration.handler {
126
127
  | Some(handler) =>
127
128
  await item->runEventHandlerOrThrow(
128
129
  ~handler,
@@ -161,7 +162,9 @@ let preloadBatchOrThrow = async (
161
162
  for idx in 0 to checkpointEventsProcessed - 1 {
162
163
  let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
163
164
  switch item {
164
- | Event({eventConfig: {handler, contractName, name: eventName}}) =>
165
+ | Event(_) =>
166
+ let {handler, eventConfig: {contractName, name: eventName}} =
167
+ (item->Internal.castUnsafeEventItem).onEventRegistration
165
168
  switch handler {
166
169
  | None => ()
167
170
  | Some(handler) =>
@@ -200,7 +203,7 @@ let preloadBatchOrThrow = async (
200
203
  | _ => ()
201
204
  }
202
205
  }
203
- | Block({onBlockConfig: {handler}, blockNumber}) =>
206
+ | Block({onBlockRegistration: {handler}, blockNumber}) =>
204
207
  try {
205
208
  promises->Array.push(
206
209
  handler({
@@ -264,11 +267,19 @@ let runBatchHandlersOrThrow = async (
264
267
  }
265
268
  }
266
269
 
267
- let registerProcessEventBatchMetrics = (~logger, ~loadDuration, ~handlerDuration) => {
268
- logger->Logging.childTrace({
269
- "msg": "Finished processing batch",
270
- "loader_time_elapsed": loadDuration,
271
- "handlers_time_elapsed": handlerDuration,
270
+ let registerProcessEventBatchMetrics = (
271
+ ~logger,
272
+ ~batch: Batch.t,
273
+ ~loadDuration,
274
+ ~handlerDuration,
275
+ ) => {
276
+ batch.progressedChainsById->Dict.forEachWithKey((chainAfterBatch, chainId) => {
277
+ logger->Logging.childTrace({
278
+ "msg": "Finished processing",
279
+ "chainId": chainId->Int.fromString->Option.getUnsafe,
280
+ "batchSize": chainAfterBatch.batchSize,
281
+ "progress": chainAfterBatch.progressBlockNumber,
282
+ })
272
283
  })
273
284
 
274
285
  Prometheus.ProcessingBatch.registerMetrics(~loadDuration, ~handlerDuration)
@@ -281,6 +292,39 @@ type logPartitionInfo = {
281
292
  lastItemBlockNumber?: int,
282
293
  }
283
294
 
295
+ // Off the hot path: bulk-materialise the selected transaction and block fields
296
+ // for the batch's store-backed (HyperSync) items and write them onto the
297
+ // payloads, so handlers read plain objects. A batch can span chains, each with
298
+ // its own stores and field masks, so group items by chain before materialising.
299
+ let materializeBatchEvents = async (
300
+ batch: Batch.t,
301
+ ~chainStates: dict<ChainState.t>,
302
+ ~ecosystem,
303
+ ) => {
304
+ switch chainStates->Dict.valuesToArray {
305
+ // Single-chain indexers (the common case): every item belongs to the one
306
+ // chain, so skip the per-chain grouping and its allocations.
307
+ | [cs] => await cs->ChainState.materializeBatchItems(~items=batch.items, ~ecosystem)
308
+ | _ =>
309
+ let itemsByChain: dict<array<Internal.item>> = Dict.make()
310
+ batch.items->Array.forEach(item => {
311
+ let chainId = item->Internal.getItemChainId->Int.toString
312
+ switch itemsByChain->Utils.Dict.dangerouslyGetNonOption(chainId) {
313
+ | Some(items) => items->Array.push(item)
314
+ | None => itemsByChain->Dict.set(chainId, [item])
315
+ }
316
+ })
317
+
318
+ let _ = await itemsByChain
319
+ ->Dict.toArray
320
+ ->Array.map(async ((chainId, items)) => {
321
+ let cs = chainStates->Dict.getUnsafe(chainId)
322
+ await cs->ChainState.materializeBatchItems(~items, ~ecosystem)
323
+ })
324
+ ->Promise.all
325
+ }
326
+ }
327
+
284
328
  let processEventBatch = async (
285
329
  ~batch: Batch.t,
286
330
  ~indexerState: IndexerState.t,
@@ -289,33 +333,33 @@ let processEventBatch = async (
289
333
  ~config: Config.t,
290
334
  ~chainStates: dict<ChainState.t>,
291
335
  ) => {
292
- let totalBatchSize = batch.totalBatchSize
293
336
  // Compute chains state for this batch
294
337
  let chains: Internal.chains = chainStates->computeChainsState
295
338
 
296
339
  let logger = Logging.getLogger()
297
- logger->Logging.childTrace({
298
- "msg": "Started processing batch",
299
- "totalBatchSize": totalBatchSize,
300
- "chains": batch.progressedChainsById->Utils.Dict.mapValues(chainAfterBatch => {
301
- {
302
- "batchSize": chainAfterBatch.batchSize,
303
- "progress": chainAfterBatch.progressBlockNumber,
304
- }
305
- }),
340
+
341
+ batch.progressedChainsById->Dict.forEachWithKey((chainAfterBatch, chainId) => {
342
+ logger->Logging.childTrace({
343
+ "msg": "Started processing",
344
+ "chainId": chainId->Int.fromString->Option.getUnsafe,
345
+ "batchSize": chainAfterBatch.batchSize,
346
+ })
306
347
  })
307
348
 
308
349
  try {
309
350
  // Backpressure: keep processing within keepLatestChangesLimit of the cycle.
310
351
  await indexerState->Writing.awaitCapacity
311
352
 
312
- let timeRef = Hrtime.makeTimer()
353
+ let timeRef = Performance.now()
313
354
 
314
355
  if batch.items->Utils.Array.notEmpty {
356
+ // Materialise store-backed transactions onto payloads before any handler
357
+ // (preload or execute) reads them.
358
+ await materializeBatchEvents(batch, ~chainStates, ~ecosystem=config.ecosystem.name)
315
359
  await batch->preloadBatchOrThrow(~loadManager, ~persistence, ~indexerState, ~chains, ~config)
316
360
  }
317
361
 
318
- let elapsedTimeAfterLoaders = timeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
362
+ let elapsedTimeAfterLoaders = timeRef->Performance.secondsSince
319
363
 
320
364
  if batch.items->Utils.Array.notEmpty {
321
365
  await batch->runBatchHandlersOrThrow(
@@ -327,13 +371,18 @@ let processEventBatch = async (
327
371
  )
328
372
  }
329
373
 
330
- let elapsedTimeAfterProcessing = timeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
374
+ let elapsedTimeAfterProcessing = timeRef->Performance.secondsSince
331
375
 
332
376
  indexerState->Writing.commitBatch(~batch)
333
377
 
334
378
  let loaderDuration = elapsedTimeAfterLoaders
335
379
  let handlerDuration = elapsedTimeAfterProcessing -. loaderDuration
336
- registerProcessEventBatchMetrics(~logger, ~loadDuration=loaderDuration, ~handlerDuration)
380
+ registerProcessEventBatchMetrics(
381
+ ~logger,
382
+ ~batch,
383
+ ~loadDuration=loaderDuration,
384
+ ~handlerDuration,
385
+ )
337
386
  Ok()
338
387
  } catch {
339
388
  | Persistence.StorageError({message, reason}) =>
@@ -1,13 +1,16 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Utils from "./Utils.res.mjs";
4
- import * as Hrtime from "./bindings/Hrtime.res.mjs";
5
4
  import * as Logging from "./Logging.res.mjs";
6
5
  import * as Writing from "./Writing.res.mjs";
6
+ import * as Internal from "./Internal.res.mjs";
7
7
  import * as Ecosystem from "./Ecosystem.res.mjs";
8
8
  import * as ChainState from "./ChainState.res.mjs";
9
9
  import * as Prometheus from "./Prometheus.res.mjs";
10
+ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
11
+ import * as Performance from "./bindings/Performance.res.mjs";
10
12
  import * as Persistence from "./Persistence.res.mjs";
13
+ import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
11
14
  import * as UserContext from "./UserContext.res.mjs";
12
15
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
13
16
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
@@ -33,7 +36,7 @@ function computeChainsState(chainStates) {
33
36
  let ProcessingError = /* @__PURE__ */Primitive_exceptions.create("EventProcessing.ProcessingError");
34
37
 
35
38
  async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState, loadManager, persistence, chains, config) {
36
- let timeBeforeHandler = Hrtime.makeTimer();
39
+ let timeBeforeHandler = Performance.now();
37
40
  try {
38
41
  let contextParams = {
39
42
  item: item,
@@ -61,13 +64,14 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState,
61
64
  Error: new Error()
62
65
  };
63
66
  }
64
- let handlerDuration = Hrtime.toSecondsFloat(Hrtime.timeSince(timeBeforeHandler));
65
- return Prometheus.ProcessingHandler.increment(item.eventConfig.contractName, item.eventConfig.name, handlerDuration);
67
+ let handlerDuration = Performance.secondsSince(timeBeforeHandler);
68
+ let eventConfig = item.onEventRegistration.eventConfig;
69
+ return Prometheus.ProcessingHandler.increment(eventConfig.contractName, eventConfig.name, handlerDuration);
66
70
  }
67
71
 
68
72
  async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager, persistence, config, chains) {
69
73
  if (item.kind === 0) {
70
- let handler = item.eventConfig.handler;
74
+ let handler = item.onEventRegistration.handler;
71
75
  if (handler !== undefined) {
72
76
  return await runEventHandlerOrThrow(item, checkpointId, handler, indexerState, loadManager, persistence, chains, config);
73
77
  } else {
@@ -86,7 +90,7 @@ async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager,
86
90
  config: config,
87
91
  isResolved: false
88
92
  };
89
- await item.onBlockConfig.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext(contextParams)));
93
+ await item.onBlockRegistration.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext(contextParams)));
90
94
  contextParams.isResolved = true;
91
95
  return;
92
96
  } catch (raw_exn) {
@@ -110,11 +114,12 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inde
110
114
  for (let idx = 0; idx < checkpointEventsProcessed; ++idx) {
111
115
  let item = batch.items[itemIdx + idx | 0];
112
116
  if (item.kind === 0) {
113
- let match = item.eventConfig;
117
+ let match = item.onEventRegistration;
114
118
  let handler = match.handler;
115
119
  if (handler !== undefined) {
116
- let contractName = match.contractName;
117
- let eventName = match.name;
120
+ let match$1 = match.eventConfig;
121
+ let contractName = match$1.contractName;
122
+ let eventName = match$1.name;
118
123
  try {
119
124
  let timerRef = Prometheus.PreloadHandler.startOperation(contractName, eventName);
120
125
  promises.push(Utils.$$Promise.silentCatch(handler({
@@ -137,7 +142,7 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inde
137
142
  }
138
143
  } else {
139
144
  try {
140
- promises.push(Utils.$$Promise.silentCatch(item.onBlockConfig.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext({
145
+ promises.push(Utils.$$Promise.silentCatch(item.onBlockRegistration.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext({
141
146
  item: item,
142
147
  checkpointId: checkpointId,
143
148
  indexerState: indexerState,
@@ -171,41 +176,62 @@ async function runBatchHandlersOrThrow(batch, indexerState, loadManager, persist
171
176
  }
172
177
  }
173
178
 
174
- function registerProcessEventBatchMetrics(logger, loadDuration, handlerDuration) {
175
- Logging.childTrace(logger, {
176
- msg: "Finished processing batch",
177
- loader_time_elapsed: loadDuration,
178
- handlers_time_elapsed: handlerDuration
179
- });
179
+ function registerProcessEventBatchMetrics(logger, batch, loadDuration, handlerDuration) {
180
+ Stdlib_Dict.forEachWithKey(batch.progressedChainsById, (chainAfterBatch, chainId) => Logging.childTrace(logger, {
181
+ msg: "Finished processing",
182
+ chainId: Stdlib_Int.fromString(chainId, undefined),
183
+ batchSize: chainAfterBatch.batchSize,
184
+ progress: chainAfterBatch.progressBlockNumber
185
+ }));
180
186
  Prometheus.ProcessingBatch.registerMetrics(loadDuration, handlerDuration);
181
187
  }
182
188
 
189
+ async function materializeBatchEvents(batch, chainStates, ecosystem) {
190
+ let match = Object.values(chainStates);
191
+ if (match.length !== 1) {
192
+ let itemsByChain = {};
193
+ batch.items.forEach(item => {
194
+ let chainId = Internal.getItemChainId(item).toString();
195
+ let items = itemsByChain[chainId];
196
+ if (items !== undefined) {
197
+ items.push(item);
198
+ } else {
199
+ itemsByChain[chainId] = [item];
200
+ }
201
+ });
202
+ await Promise.all(Object.entries(itemsByChain).map(async param => {
203
+ let cs = chainStates[param[0]];
204
+ return await ChainState.materializeBatchItems(cs, param[1], ecosystem);
205
+ }));
206
+ return;
207
+ }
208
+ let cs = match[0];
209
+ return await ChainState.materializeBatchItems(cs, batch.items, ecosystem);
210
+ }
211
+
183
212
  async function processEventBatch(batch, indexerState, loadManager, persistence, config, chainStates) {
184
- let totalBatchSize = batch.totalBatchSize;
185
213
  let chains = computeChainsState(chainStates);
186
214
  let logger = Logging.getLogger();
187
- Logging.childTrace(logger, {
188
- msg: "Started processing batch",
189
- totalBatchSize: totalBatchSize,
190
- chains: Utils.Dict.mapValues(batch.progressedChainsById, chainAfterBatch => ({
191
- batchSize: chainAfterBatch.batchSize,
192
- progress: chainAfterBatch.progressBlockNumber
193
- }))
194
- });
215
+ Stdlib_Dict.forEachWithKey(batch.progressedChainsById, (chainAfterBatch, chainId) => Logging.childTrace(logger, {
216
+ msg: "Started processing",
217
+ chainId: Stdlib_Int.fromString(chainId, undefined),
218
+ batchSize: chainAfterBatch.batchSize
219
+ }));
195
220
  try {
196
221
  await Writing.awaitCapacity(indexerState);
197
- let timeRef = Hrtime.makeTimer();
222
+ let timeRef = Performance.now();
198
223
  if (Utils.$$Array.notEmpty(batch.items)) {
224
+ await materializeBatchEvents(batch, chainStates, config.ecosystem.name);
199
225
  await preloadBatchOrThrow(batch, loadManager, persistence, config, indexerState, chains);
200
226
  }
201
- let elapsedTimeAfterLoaders = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef));
227
+ let elapsedTimeAfterLoaders = Performance.secondsSince(timeRef);
202
228
  if (Utils.$$Array.notEmpty(batch.items)) {
203
229
  await runBatchHandlersOrThrow(batch, indexerState, loadManager, persistence, config, chains);
204
230
  }
205
- let elapsedTimeAfterProcessing = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef));
231
+ let elapsedTimeAfterProcessing = Performance.secondsSince(timeRef);
206
232
  Writing.commitBatch(indexerState, batch);
207
233
  let handlerDuration = elapsedTimeAfterProcessing - elapsedTimeAfterLoaders;
208
- registerProcessEventBatchMetrics(logger, elapsedTimeAfterLoaders, handlerDuration);
234
+ registerProcessEventBatchMetrics(logger, batch, elapsedTimeAfterLoaders, handlerDuration);
209
235
  return {
210
236
  TAG: "Ok",
211
237
  _0: undefined
@@ -240,6 +266,7 @@ export {
240
266
  preloadBatchOrThrow,
241
267
  runBatchHandlersOrThrow,
242
268
  registerProcessEventBatchMetrics,
269
+ materializeBatchEvents,
243
270
  processEventBatch,
244
271
  }
245
272
  /* Utils Not a pure module */
@@ -4,7 +4,15 @@ let run = async (state: IndexerState.t) => {
4
4
  ChainMetadata.stage(state)
5
5
  await state->Writing.flush
6
6
  if !(state->IndexerState.isStopped) && !(state->IndexerState.isResolvingReorg) {
7
- Logging.info("Exiting with success")
8
- NodeJs.process->NodeJs.exitWithCode(Success)
7
+ // A simulate run fails here when a provided item never reached a handler —
8
+ // dead test code. The tracker is None (a no-op) off the simulate path.
9
+ switch state
10
+ ->IndexerState.simulateDeadInputTracker
11
+ ->Option.flatMap(SimulateDeadInputTracker.failureMessage) {
12
+ | None =>
13
+ Logging.info("Exiting with success")
14
+ NodeJs.process->NodeJs.exitWithCode(Success)
15
+ | Some(message) => state->IndexerState.errorExit(ErrorHandling.make(Utils.Error.make(message)))
16
+ }
9
17
  }
10
18
  }