envio 3.3.0-alpha.7 → 3.3.0-alpha.8

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 (89) hide show
  1. package/index.d.ts +23 -5
  2. package/package.json +6 -6
  3. package/src/Api.res +1 -1
  4. package/src/Api.res.mjs +1 -1
  5. package/src/ChainFetching.res +21 -10
  6. package/src/ChainFetching.res.mjs +11 -10
  7. package/src/ChainState.res +328 -165
  8. package/src/ChainState.res.mjs +205 -100
  9. package/src/ChainState.resi +16 -7
  10. package/src/Config.res +11 -27
  11. package/src/Config.res.mjs +8 -7
  12. package/src/Core.res +7 -0
  13. package/src/CrossChainState.res +53 -80
  14. package/src/CrossChainState.res.mjs +43 -59
  15. package/src/CrossChainState.resi +1 -1
  16. package/src/Ecosystem.res +3 -3
  17. package/src/Ecosystem.res.mjs +3 -3
  18. package/src/Envio.res +14 -9
  19. package/src/EventConfigBuilder.res +105 -56
  20. package/src/EventConfigBuilder.res.mjs +69 -33
  21. package/src/EventProcessing.res +19 -15
  22. package/src/EventProcessing.res.mjs +13 -12
  23. package/src/FetchState.res +375 -171
  24. package/src/FetchState.res.mjs +249 -251
  25. package/src/HandlerLoader.res +7 -112
  26. package/src/HandlerLoader.res.mjs +1 -87
  27. package/src/HandlerRegister.res +209 -6
  28. package/src/HandlerRegister.res.mjs +90 -5
  29. package/src/HandlerRegister.resi +13 -2
  30. package/src/IndexerState.res +6 -3
  31. package/src/IndexerState.res.mjs +3 -3
  32. package/src/IndexerState.resi +1 -1
  33. package/src/IndexingAddresses.res +10 -7
  34. package/src/IndexingAddresses.res.mjs +8 -7
  35. package/src/IndexingAddresses.resi +3 -1
  36. package/src/Internal.res +82 -36
  37. package/src/Internal.res.mjs +11 -1
  38. package/src/Main.res +22 -23
  39. package/src/Main.res.mjs +15 -17
  40. package/src/Metrics.res +43 -2
  41. package/src/Metrics.res.mjs +39 -3
  42. package/src/Prometheus.res +0 -35
  43. package/src/Prometheus.res.mjs +33 -68
  44. package/src/RawEvent.res +7 -2
  45. package/src/RawEvent.res.mjs +4 -4
  46. package/src/SimulateItems.res +20 -7
  47. package/src/SimulateItems.res.mjs +7 -11
  48. package/src/TestIndexer.res +1 -1
  49. package/src/TestIndexer.res.mjs +1 -1
  50. package/src/sources/BlockStore.res +46 -0
  51. package/src/sources/BlockStore.res.mjs +24 -0
  52. package/src/sources/EventRouter.res +19 -12
  53. package/src/sources/EventRouter.res.mjs +7 -5
  54. package/src/sources/Evm.res +54 -4
  55. package/src/sources/Evm.res.mjs +43 -4
  56. package/src/sources/EvmChain.res +14 -18
  57. package/src/sources/EvmChain.res.mjs +12 -13
  58. package/src/sources/FieldMask.res +39 -0
  59. package/src/sources/FieldMask.res.mjs +42 -0
  60. package/src/sources/Fuel.res +5 -2
  61. package/src/sources/Fuel.res.mjs +4 -3
  62. package/src/sources/HyperFuelSource.res +31 -40
  63. package/src/sources/HyperFuelSource.res.mjs +52 -44
  64. package/src/sources/HyperSync.res +31 -9
  65. package/src/sources/HyperSync.res.mjs +47 -31
  66. package/src/sources/HyperSync.resi +10 -3
  67. package/src/sources/HyperSyncClient.res +15 -4
  68. package/src/sources/HyperSyncHeightStream.res +1 -8
  69. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  70. package/src/sources/HyperSyncSource.res +37 -58
  71. package/src/sources/HyperSyncSource.res.mjs +42 -42
  72. package/src/sources/RpcSource.res +91 -82
  73. package/src/sources/RpcSource.res.mjs +76 -45
  74. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  75. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  76. package/src/sources/SimulateSource.res +5 -3
  77. package/src/sources/SimulateSource.res.mjs +12 -4
  78. package/src/sources/Source.res +19 -5
  79. package/src/sources/SourceManager.res +62 -6
  80. package/src/sources/SourceManager.res.mjs +55 -8
  81. package/src/sources/SourceManager.resi +10 -0
  82. package/src/sources/Svm.res +14 -10
  83. package/src/sources/Svm.res.mjs +23 -6
  84. package/src/sources/SvmHyperSyncClient.res +5 -6
  85. package/src/sources/SvmHyperSyncSource.res +82 -41
  86. package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
  87. package/src/sources/TransactionStore.res +6 -107
  88. package/src/sources/TransactionStore.res.mjs +5 -86
  89. package/svm.schema.json +19 -0
@@ -48,18 +48,16 @@ let getKnownRawBlockWithBackoff = async (
48
48
  ~chain,
49
49
  ~blockNumber,
50
50
  ~backoffMsOnFailure,
51
+ ~recordRequest: (~method: string, ~seconds: float) => unit,
51
52
  ) => {
52
53
  let currentBackoff = ref(backoffMsOnFailure)
53
54
  let result = ref(None)
54
55
 
55
56
  while result.contents->Option.isNone {
56
- Prometheus.SourceRequestCount.increment(
57
- ~sourceName,
58
- ~chainId=chain->ChainMap.Chain.toChainId,
59
- ~method="eth_getBlockByNumber",
60
- )
57
+ let timerRef = Performance.now()
61
58
  switch await getKnownRawBlock(~client, ~blockNumber) {
62
59
  | exception err =>
60
+ recordRequest(~method="eth_getBlockByNumber", ~seconds=timerRef->Performance.secondsSince)
63
61
  Logging.warn({
64
62
  "err": err->Utils.prettifyExn,
65
63
  "msg": `Issue while running fetching batch of events from the RPC. Will wait ${currentBackoff.contents->Int.toString}ms and try again.`,
@@ -69,7 +67,9 @@ let getKnownRawBlockWithBackoff = async (
69
67
  })
70
68
  await Time.resolvePromiseAfterDelay(~delayMilliseconds=currentBackoff.contents)
71
69
  currentBackoff := currentBackoff.contents * 2
72
- | json => result := Some(json)
70
+ | json =>
71
+ recordRequest(~method="eth_getBlockByNumber", ~seconds=timerRef->Performance.secondsSince)
72
+ result := Some(json)
73
73
  }
74
74
  }
75
75
  result.contents->Option.getOrThrow
@@ -300,8 +300,7 @@ let getNextPage = (
300
300
  ~rpcClient: EvmRpcClient.t,
301
301
  ~mutSuggestedBlockIntervals,
302
302
  ~partitionId,
303
- ~sourceName,
304
- ~chainId,
303
+ ~recordRequest: (~method: string, ~seconds: float) => unit,
305
304
  ): promise<eventBatchQuery> => {
306
305
  //If the query hangs for longer than this, reject this promise to reduce the block interval
307
306
  let queryTimoutPromise =
@@ -314,7 +313,7 @@ let getNextPage = (
314
313
  let latestFetchedBlockPromise = loadBlock(toBlock)
315
314
 
316
315
  let queryLogs = ({addresses, topicQuery}: logSelection) => {
317
- Prometheus.SourceRequestCount.increment(~sourceName, ~chainId, ~method="eth_getLogs")
316
+ let timerRef = Performance.now()
318
317
  rpcClient.getLogs({
319
318
  fromBlock,
320
319
  toBlock,
@@ -326,6 +325,9 @@ let getNextPage = (
326
325
  | Multiple(topics) => Nullable.make(topics)
327
326
  }
328
327
  ),
328
+ })->Promise.thenResolve(items => {
329
+ recordRequest(~method="eth_getLogs", ~seconds=timerRef->Performance.secondsSince)
330
+ items
329
331
  })
330
332
  }
331
333
 
@@ -411,12 +413,12 @@ type selectionConfig = {
411
413
  }
412
414
 
413
415
  let getSelectionConfig = (selection: FetchState.selection, ~chain) => {
414
- let evmEventConfigs =
415
- selection.eventConfigs->(
416
- Utils.magic: array<Internal.eventConfig> => array<Internal.evmEventConfig>
416
+ let evmOnEventRegistrations =
417
+ selection.onEventRegistrations->(
418
+ Utils.magic: array<Internal.onEventRegistration> => array<Internal.evmOnEventRegistration>
417
419
  )
418
420
 
419
- if evmEventConfigs->Utils.Array.isEmpty {
421
+ if evmOnEventRegistrations->Utils.Array.isEmpty {
420
422
  throw(
421
423
  Source.GetItemsError(
422
424
  UnsupportedSelection({
@@ -439,12 +441,9 @@ let getSelectionConfig = (selection: FetchState.selection, ~chain) => {
439
441
  let dynamicWildcardByContract = Dict.make()
440
442
  let contractNames = Utils.Set.make()
441
443
 
442
- evmEventConfigs->Array.forEach(({
443
- contractName,
444
- isWildcard,
445
- dependsOnAddresses,
446
- getEventFiltersOrThrow,
447
- }) => {
444
+ evmOnEventRegistrations->Array.forEach(reg => {
445
+ let contractName = reg.eventConfig.contractName
446
+ let {isWildcard, dependsOnAddresses, getEventFiltersOrThrow} = reg
448
447
  let eventFilters = getEventFiltersOrThrow(chain)
449
448
  if dependsOnAddresses {
450
449
  contractNames->Utils.Set.add(contractName)->ignore
@@ -674,11 +673,9 @@ let makeThrowingGetEventBlock = (
674
673
  }
675
674
  }
676
675
 
677
- // `number`, `timestamp` and `hash` are always part of the selected block
678
- // fields, so they can be read from the assembled block at item construction.
676
+ // `number` is always part of the selected block fields, so it can be read
677
+ // from the assembled block for the item's own `blockNumber`.
679
678
  @get external getBlockNumber: Internal.eventBlock => int = "number"
680
- @get external getBlockTimestamp: Internal.eventBlock => int = "timestamp"
681
- @get external getBlockHash: Internal.eventBlock => string = "hash"
682
679
 
683
680
  // Field source classification for RPC calls
684
681
  type fieldSource = TransactionOnly | ReceiptOnly | Both
@@ -994,7 +991,7 @@ type options = {
994
991
  syncConfig: Config.sourceSync,
995
992
  url: string,
996
993
  chain: ChainMap.Chain.t,
997
- eventRouter: EventRouter.t<Internal.evmEventConfig>,
994
+ eventRouter: EventRouter.t<Internal.evmOnEventRegistration>,
998
995
  allEventParams: array<HyperSyncClient.Decoder.eventParamsInput>,
999
996
  lowercaseAddresses: bool,
1000
997
  ws?: string,
@@ -1040,15 +1037,37 @@ let make = (
1040
1037
  ~headers?,
1041
1038
  )
1042
1039
 
1040
+ // Requests are made from shared, memoized loaders, so they can't be
1041
+ // attributed to a single getItemsOrThrow/getHeightOrThrow/getBlockHashes
1042
+ // call at its call site. Every actual request (cache/dedup hits never reach
1043
+ // recordRequest) pushes here; each method drains whatever is pending when it
1044
+ // returns. Since a push always lands in exactly one drain, per-source totals
1045
+ // stay exact even with concurrent in-flight calls — which call happens to
1046
+ // drain a given entry doesn't matter, since SourceManager aggregates by
1047
+ // (source, method) regardless of which call returned it.
1048
+ let pendingRequestStats: array<Source.requestStat> = []
1049
+ let recordRequest = (~method, ~seconds) => {
1050
+ pendingRequestStats->Array.push({Source.method, seconds})->ignore
1051
+ }
1052
+ let drainRequestStats = () => {
1053
+ let stats = pendingRequestStats->Utils.Array.copy
1054
+ pendingRequestStats->Utils.Array.clearInPlace
1055
+ stats
1056
+ }
1057
+
1043
1058
  let makeTransactionLoader = () =>
1044
1059
  LazyLoader.make(
1045
1060
  ~loaderFn=transactionHash => {
1046
- Prometheus.SourceRequestCount.increment(
1047
- ~sourceName=name,
1048
- ~chainId=chain->ChainMap.Chain.toChainId,
1049
- ~method="eth_getTransactionByHash",
1050
- )
1051
- Rpc.GetTransactionByHash.rawRoute->Rest.fetch(transactionHash, ~client)
1061
+ let timerRef = Performance.now()
1062
+ Rpc.GetTransactionByHash.rawRoute
1063
+ ->Rest.fetch(transactionHash, ~client)
1064
+ ->Promise.thenResolve(res => {
1065
+ recordRequest(
1066
+ ~method="eth_getTransactionByHash",
1067
+ ~seconds=timerRef->Performance.secondsSince,
1068
+ )
1069
+ res
1070
+ })
1052
1071
  },
1053
1072
  ~onError=(am, ~exn) => {
1054
1073
  Logging.error({
@@ -1076,6 +1095,7 @@ let make = (
1076
1095
  ~chain,
1077
1096
  ~backoffMsOnFailure=1000,
1078
1097
  ~blockNumber,
1098
+ ~recordRequest,
1079
1099
  )
1080
1100
  },
1081
1101
  ~onError=(am, ~exn) => {
@@ -1098,12 +1118,16 @@ let make = (
1098
1118
  let makeReceiptLoader = () =>
1099
1119
  LazyLoader.make(
1100
1120
  ~loaderFn=transactionHash => {
1101
- Prometheus.SourceRequestCount.increment(
1102
- ~sourceName=name,
1103
- ~chainId=chain->ChainMap.Chain.toChainId,
1104
- ~method="eth_getTransactionReceipt",
1105
- )
1106
- Rpc.GetTransactionReceipt.rawRoute->Rest.fetch(transactionHash, ~client)
1121
+ let timerRef = Performance.now()
1122
+ Rpc.GetTransactionReceipt.rawRoute
1123
+ ->Rest.fetch(transactionHash, ~client)
1124
+ ->Promise.thenResolve(res => {
1125
+ recordRequest(
1126
+ ~method="eth_getTransactionReceipt",
1127
+ ~seconds=timerRef->Performance.secondsSince,
1128
+ )
1129
+ res
1130
+ })
1107
1131
  },
1108
1132
  ~onError=(am, ~exn) => {
1109
1133
  Logging.error({
@@ -1211,8 +1235,7 @@ let make = (
1211
1235
  ~rpcClient,
1212
1236
  ~mutSuggestedBlockIntervals,
1213
1237
  ~partitionId,
1214
- ~sourceName=name,
1215
- ~chainId=chain->ChainMap.Chain.toChainId,
1238
+ ~recordRequest,
1216
1239
  )
1217
1240
 
1218
1241
  let executedBlockInterval = suggestedToBlock - fromBlock + 1
@@ -1246,7 +1269,11 @@ let make = (
1246
1269
  ~contractAddress=routedAddress,
1247
1270
  ) {
1248
1271
  | None => None
1249
- | Some(eventConfig) =>
1272
+ | Some(onEventRegistration) =>
1273
+ let eventConfig =
1274
+ onEventRegistration.eventConfig->(
1275
+ Utils.magic: Internal.eventConfig => Internal.evmEventConfig
1276
+ )
1250
1277
  switch maybeDecodedEvent
1251
1278
  ->Nullable.toOption
1252
1279
  ->Option.flatMap(Dict.get(_, eventConfig.contractName)) {
@@ -1293,10 +1320,8 @@ let make = (
1293
1320
  }
1294
1321
 
1295
1322
  Internal.Event({
1296
- eventConfig: (eventConfig :> Internal.eventConfig),
1297
- timestamp: block->getBlockTimestamp,
1323
+ onEventRegistration: (onEventRegistration :> Internal.onEventRegistration),
1298
1324
  blockNumber: block->getBlockNumber,
1299
- blockHash: block->getBlockHash,
1300
1325
  chain,
1301
1326
  logIndex: log.logIndex,
1302
1327
  transactionIndex: log.transactionIndex,
@@ -1350,14 +1375,16 @@ let make = (
1350
1375
  latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
1351
1376
  latestFetchedBlockNumber: latestFetchedBlockInfo.number,
1352
1377
  parsedQueueItems,
1353
- // RPC keeps the transaction inline on the payload; no store page.
1378
+ // RPC keeps the transaction and block inline on the payload; no store pages.
1354
1379
  transactionStore: None,
1380
+ blockStore: None,
1355
1381
  stats: {
1356
1382
  totalTimeElapsed: totalTimeElapsed,
1357
1383
  },
1358
1384
  knownHeight,
1359
1385
  blockHashes,
1360
1386
  fromBlockQueried: fromBlock,
1387
+ requestStats: drainRequestStats(),
1361
1388
  }
1362
1389
  }
1363
1390
 
@@ -1374,21 +1401,25 @@ let make = (
1374
1401
  ->Array.map(blockNum => blockLoader.contents->LazyLoader.get(blockNum))
1375
1402
  ->Promise.all
1376
1403
  ->Promise.thenResolve(rawBlocks => {
1377
- rawBlocks
1378
- ->Array.map(json => {
1379
- let b = parseBlockInfo(json)
1380
-
1381
- (
1382
- {
1383
- blockNumber: b.number,
1384
- blockHash: b.hash,
1385
- blockTimestamp: b.timestamp,
1386
- }: ReorgDetection.blockDataWithTimestamp
1387
- )
1388
- })
1389
- ->Ok
1404
+ let result =
1405
+ rawBlocks
1406
+ ->Array.map(json => {
1407
+ let b = parseBlockInfo(json)
1408
+
1409
+ (
1410
+ {
1411
+ blockNumber: b.number,
1412
+ blockHash: b.hash,
1413
+ blockTimestamp: b.timestamp,
1414
+ }: ReorgDetection.blockDataWithTimestamp
1415
+ )
1416
+ })
1417
+ ->Ok
1418
+ {Source.result, requestStats: drainRequestStats()}
1390
1419
  })
1391
- ->Promise.catch(exn => exn->Error->Promise.resolve)
1420
+ ->Promise.catch(exn =>
1421
+ {Source.result: Error(exn), requestStats: drainRequestStats()}->Promise.resolve
1422
+ )
1392
1423
  }
1393
1424
 
1394
1425
  let createHeightSubscription =
@@ -1410,33 +1441,11 @@ let make = (
1410
1441
  await rpcClient.getHeight()
1411
1442
  } catch {
1412
1443
  | exn =>
1413
- let seconds = timerRef->Performance.secondsSince
1414
- Prometheus.SourceRequestCount.increment(
1415
- ~sourceName=name,
1416
- ~chainId=chain->ChainMap.Chain.toChainId,
1417
- ~method="eth_blockNumber",
1418
- )
1419
- Prometheus.SourceRequestCount.addSeconds(
1420
- ~sourceName=name,
1421
- ~chainId=chain->ChainMap.Chain.toChainId,
1422
- ~method="eth_blockNumber",
1423
- ~seconds,
1424
- )
1444
+ recordRequest(~method="eth_blockNumber", ~seconds=timerRef->Performance.secondsSince)
1425
1445
  exn->throw
1426
1446
  }
1427
- let seconds = timerRef->Performance.secondsSince
1428
- Prometheus.SourceRequestCount.increment(
1429
- ~sourceName=name,
1430
- ~chainId=chain->ChainMap.Chain.toChainId,
1431
- ~method="eth_blockNumber",
1432
- )
1433
- Prometheus.SourceRequestCount.addSeconds(
1434
- ~sourceName=name,
1435
- ~chainId=chain->ChainMap.Chain.toChainId,
1436
- ~method="eth_blockNumber",
1437
- ~seconds,
1438
- )
1439
- height
1447
+ recordRequest(~method="eth_blockNumber", ~seconds=timerRef->Performance.secondsSince)
1448
+ {height, requestStats: drainRequestStats()}
1440
1449
  },
1441
1450
  getItemsOrThrow,
1442
1451
  ?createHeightSubscription,
@@ -9,7 +9,6 @@ import * as Address from "../Address.res.mjs";
9
9
  import * as Logging from "../Logging.res.mjs";
10
10
  import * as Internal from "../Internal.res.mjs";
11
11
  import * as LazyLoader from "../LazyLoader.res.mjs";
12
- import * as Prometheus from "../Prometheus.res.mjs";
13
12
  import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
14
13
  import * as EventRouter from "./EventRouter.res.mjs";
15
14
  import * as Performance from "../bindings/Performance.res.mjs";
@@ -47,11 +46,11 @@ function parseBlockInfo(json) {
47
46
  };
48
47
  }
49
48
 
50
- async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumber, backoffMsOnFailure) {
49
+ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumber, backoffMsOnFailure, recordRequest) {
51
50
  let currentBackoff = backoffMsOnFailure;
52
51
  let result;
53
52
  while (Stdlib_Option.isNone(result)) {
54
- Prometheus.SourceRequestCount.increment(sourceName, chain, "eth_getBlockByNumber");
53
+ let timerRef = Performance.now();
55
54
  let exit = 0;
56
55
  let json;
57
56
  try {
@@ -59,6 +58,7 @@ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumbe
59
58
  exit = 1;
60
59
  } catch (raw_err) {
61
60
  let err = Primitive_exceptions.internalToException(raw_err);
61
+ recordRequest("eth_getBlockByNumber", Performance.secondsSince(timerRef));
62
62
  Logging.warn({
63
63
  err: Utils.prettifyExn(err),
64
64
  msg: `Issue while running fetching batch of events from the RPC. Will wait ` + currentBackoff.toString() + `ms and try again.`,
@@ -70,6 +70,7 @@ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumbe
70
70
  currentBackoff = (currentBackoff << 1);
71
71
  }
72
72
  if (exit === 1) {
73
+ recordRequest("eth_getBlockByNumber", Performance.secondsSince(timerRef));
73
74
  result = json;
74
75
  }
75
76
  };
@@ -265,14 +266,14 @@ function mergeAndDedupItems(itemsPerSelection) {
265
266
  return merged;
266
267
  }
267
268
 
268
- function getNextPage(fromBlock, toBlock, logSelections, loadBlock, sc, rpcClient, mutSuggestedBlockIntervals, partitionId, sourceName, chainId) {
269
+ function getNextPage(fromBlock, toBlock, logSelections, loadBlock, sc, rpcClient, mutSuggestedBlockIntervals, partitionId, recordRequest) {
269
270
  let queryTimoutPromise = Time.resolvePromiseAfterDelay(sc.queryTimeoutMillis).then(() => Promise.reject({
270
271
  RE_EXN_ID: QueryTimout,
271
272
  _1: `Query took longer than ` + (sc.queryTimeoutMillis / 1000 | 0).toString() + ` seconds`
272
273
  }));
273
274
  let latestFetchedBlockPromise = loadBlock(toBlock);
274
275
  let queryLogs = param => {
275
- Prometheus.SourceRequestCount.increment(sourceName, chainId, "eth_getLogs");
276
+ let timerRef = Performance.now();
276
277
  return rpcClient.getLogs({
277
278
  fromBlock: fromBlock,
278
279
  toBlock: toBlock,
@@ -286,6 +287,9 @@ function getNextPage(fromBlock, toBlock, logSelections, loadBlock, sc, rpcClient
286
287
  return filter;
287
288
  }
288
289
  })
290
+ }).then(items => {
291
+ recordRequest("eth_getLogs", Performance.secondsSince(timerRef));
292
+ return items;
289
293
  });
290
294
  };
291
295
  let len = logSelections.length;
@@ -353,8 +357,8 @@ function getNextPage(fromBlock, toBlock, logSelections, loadBlock, sc, rpcClient
353
357
  }
354
358
 
355
359
  function getSelectionConfig(selection, chain) {
356
- let evmEventConfigs = selection.eventConfigs;
357
- if (Utils.$$Array.isEmpty(evmEventConfigs)) {
360
+ let evmOnEventRegistrations = selection.onEventRegistrations;
361
+ if (Utils.$$Array.isEmpty(evmOnEventRegistrations)) {
358
362
  throw {
359
363
  RE_EXN_ID: Source.GetItemsError,
360
364
  _1: {
@@ -369,15 +373,15 @@ function getSelectionConfig(selection, chain) {
369
373
  let dynamicByContract = {};
370
374
  let dynamicWildcardByContract = {};
371
375
  let contractNames = new Set();
372
- evmEventConfigs.forEach(param => {
373
- let contractName = param.contractName;
374
- let eventFilters = param.getEventFiltersOrThrow(chain);
375
- if (param.dependsOnAddresses) {
376
+ evmOnEventRegistrations.forEach(reg => {
377
+ let contractName = reg.eventConfig.contractName;
378
+ let eventFilters = reg.getEventFiltersOrThrow(chain);
379
+ if (reg.dependsOnAddresses) {
376
380
  contractNames.add(contractName);
377
381
  if (eventFilters.TAG === "Static") {
378
382
  return Utils.Dict.pushMany(staticByContract, contractName, eventFilters._0);
379
383
  } else {
380
- return Utils.Dict.push(param.isWildcard ? dynamicWildcardByContract : dynamicByContract, contractName, eventFilters._0);
384
+ return Utils.Dict.push(reg.isWildcard ? dynamicWildcardByContract : dynamicByContract, contractName, eventFilters._0);
381
385
  }
382
386
  }
383
387
  let tmp;
@@ -973,9 +977,24 @@ function make(param) {
973
977
  let mutSuggestedBlockIntervals = {};
974
978
  let client = Rpc.makeClient(url, headers);
975
979
  let rpcClient = EvmRpcClient.make(url, !lowercaseAddresses, undefined, headers, param.allEventParams);
980
+ let pendingRequestStats = [];
981
+ let recordRequest = (method, seconds) => {
982
+ pendingRequestStats.push({
983
+ method: method,
984
+ seconds: seconds
985
+ });
986
+ };
987
+ let drainRequestStats = () => {
988
+ let stats = pendingRequestStats.slice();
989
+ Utils.$$Array.clearInPlace(pendingRequestStats);
990
+ return stats;
991
+ };
976
992
  let makeTransactionLoader = () => LazyLoader.make(transactionHash => {
977
- Prometheus.SourceRequestCount.increment(name, chain, "eth_getTransactionByHash");
978
- return Rest.fetch(Rpc.GetTransactionByHash.rawRoute, transactionHash, client);
993
+ let timerRef = Performance.now();
994
+ return Rest.fetch(Rpc.GetTransactionByHash.rawRoute, transactionHash, client).then(res => {
995
+ recordRequest("eth_getTransactionByHash", Performance.secondsSince(timerRef));
996
+ return res;
997
+ });
979
998
  }, (am, exn) => Logging.error({
980
999
  err: Utils.prettifyExn(exn),
981
1000
  msg: `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ` + (am._retryDelayMillis / 1000 | 0).toString() + ` seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
@@ -986,7 +1005,7 @@ function make(param) {
986
1005
  suggestedFix: "This likely means the RPC url you are using is not responding correctly. Please try another RPC endipoint."
987
1006
  }
988
1007
  }), undefined, undefined, undefined, undefined);
989
- let makeBlockLoader = () => LazyLoader.make(blockNumber => getKnownRawBlockWithBackoff(client, name, chain, blockNumber, 1000), (am, exn) => Logging.error({
1008
+ let makeBlockLoader = () => LazyLoader.make(blockNumber => getKnownRawBlockWithBackoff(client, name, chain, blockNumber, 1000, recordRequest), (am, exn) => Logging.error({
990
1009
  err: Utils.prettifyExn(exn),
991
1010
  msg: `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ` + (am._retryDelayMillis / 1000 | 0).toString() + ` seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
992
1011
  source: name,
@@ -997,8 +1016,11 @@ function make(param) {
997
1016
  }
998
1017
  }), undefined, undefined, undefined, undefined);
999
1018
  let makeReceiptLoader = () => LazyLoader.make(transactionHash => {
1000
- Prometheus.SourceRequestCount.increment(name, chain, "eth_getTransactionReceipt");
1001
- return Rest.fetch(Rpc.GetTransactionReceipt.rawRoute, transactionHash, client);
1019
+ let timerRef = Performance.now();
1020
+ return Rest.fetch(Rpc.GetTransactionReceipt.rawRoute, transactionHash, client).then(res => {
1021
+ recordRequest("eth_getTransactionReceipt", Performance.secondsSince(timerRef));
1022
+ return res;
1023
+ });
1002
1024
  }, (am, exn) => Logging.error({
1003
1025
  err: Utils.prettifyExn(exn),
1004
1026
  msg: `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ` + (am._retryDelayMillis / 1000 | 0).toString() + ` seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
@@ -1049,7 +1071,7 @@ function make(param) {
1049
1071
  let firstBlockParentPromise = fromBlock > 0 ? LazyLoader.get(blockLoader.contents, fromBlock - 1 | 0).then(json => parseBlockInfo(json)) : Promise.resolve(undefined);
1050
1072
  let match = getSelectionConfig(selection);
1051
1073
  let logSelections = match.getLogSelectionsOrThrow(addressesByContractName);
1052
- let match$1 = await getNextPage(fromBlock, suggestedToBlock, logSelections, blockNumber => LazyLoader.get(blockLoader.contents, blockNumber).then(parseBlockInfo), syncConfig, rpcClient, mutSuggestedBlockIntervals, partitionId, name, chain);
1074
+ let match$1 = await getNextPage(fromBlock, suggestedToBlock, logSelections, blockNumber => LazyLoader.get(blockLoader.contents, blockNumber).then(parseBlockInfo), syncConfig, rpcClient, mutSuggestedBlockIntervals, partitionId, recordRequest);
1053
1075
  let latestFetchedBlockInfo = match$1.latestFetchedBlockInfo;
1054
1076
  let items = match$1.items;
1055
1077
  let executedBlockInterval = (suggestedToBlock - fromBlock | 0) + 1 | 0;
@@ -1060,10 +1082,11 @@ function make(param) {
1060
1082
  let log = param.log;
1061
1083
  let topic0 = Stdlib_Option.getOr(log.topics[0], "0x0");
1062
1084
  let routedAddress = lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(log.address) : Address.Evm.fromAddressOrThrow(log.address);
1063
- let eventConfig = EventRouter.get(eventRouter, EventRouter.getEvmEventId(topic0, log.topics.length), routedAddress, contractNameByAddress);
1064
- if (eventConfig === undefined) {
1085
+ let onEventRegistration = EventRouter.get(eventRouter, EventRouter.getEvmEventId(topic0, log.topics.length), routedAddress, contractNameByAddress);
1086
+ if (onEventRegistration === undefined) {
1065
1087
  return;
1066
1088
  }
1089
+ let eventConfig = onEventRegistration.eventConfig;
1067
1090
  let decoded = Stdlib_Option.flatMap(Primitive_option.fromNullable(param.params), __x => __x[eventConfig.contractName]);
1068
1091
  if (decoded === undefined) {
1069
1092
  return;
@@ -1110,11 +1133,9 @@ function make(param) {
1110
1133
  let block = match[0];
1111
1134
  return {
1112
1135
  kind: 0,
1113
- eventConfig: eventConfig,
1114
- timestamp: block.timestamp,
1136
+ onEventRegistration: onEventRegistration,
1115
1137
  chain: chain,
1116
1138
  blockNumber: block.number,
1117
- blockHash: block.hash,
1118
1139
  logIndex: log.logIndex,
1119
1140
  transactionIndex: log.transactionIndex,
1120
1141
  payload: {
@@ -1125,7 +1146,7 @@ function make(param) {
1125
1146
  srcAddress: routedAddress,
1126
1147
  logIndex: log.logIndex,
1127
1148
  transaction: Primitive_option.some(match[1]),
1128
- block: block
1149
+ block: Primitive_option.some(block)
1129
1150
  }
1130
1151
  };
1131
1152
  })();
@@ -1162,12 +1183,14 @@ function make(param) {
1162
1183
  blockHashes: blockHashes,
1163
1184
  parsedQueueItems: parsedQueueItems,
1164
1185
  transactionStore: undefined,
1186
+ blockStore: undefined,
1165
1187
  fromBlockQueried: fromBlock,
1166
1188
  latestFetchedBlockNumber: latestFetchedBlockInfo.number,
1167
1189
  latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
1168
1190
  stats: {
1169
1191
  "total time elapsed (s)": totalTimeElapsed
1170
- }
1192
+ },
1193
+ requestStats: drainRequestStats()
1171
1194
  };
1172
1195
  };
1173
1196
  let onReorg = param => {
@@ -1175,19 +1198,28 @@ function make(param) {
1175
1198
  transactionLoader.contents = makeTransactionLoader();
1176
1199
  receiptLoader.contents = makeReceiptLoader();
1177
1200
  };
1178
- let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => ({
1179
- TAG: "Ok",
1180
- _0: rawBlocks.map(json => {
1181
- let b = parseBlockInfo(json);
1182
- return {
1183
- blockHash: b.hash,
1184
- blockNumber: b.number,
1185
- blockTimestamp: b.timestamp
1186
- };
1187
- })
1188
- })), exn => Promise.resolve({
1189
- TAG: "Error",
1190
- _0: exn
1201
+ let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => {
1202
+ let result = {
1203
+ TAG: "Ok",
1204
+ _0: rawBlocks.map(json => {
1205
+ let b = parseBlockInfo(json);
1206
+ return {
1207
+ blockHash: b.hash,
1208
+ blockNumber: b.number,
1209
+ blockTimestamp: b.timestamp
1210
+ };
1211
+ })
1212
+ };
1213
+ return {
1214
+ result: result,
1215
+ requestStats: drainRequestStats()
1216
+ };
1217
+ }), exn => Promise.resolve({
1218
+ result: {
1219
+ TAG: "Error",
1220
+ _0: exn
1221
+ },
1222
+ requestStats: drainRequestStats()
1191
1223
  }));
1192
1224
  let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => (onHeight => RpcWebSocketHeightStream.subscribe(wsUrl, chain, onHeight)));
1193
1225
  return {
@@ -1203,15 +1235,14 @@ function make(param) {
1203
1235
  try {
1204
1236
  height = await rpcClient.getHeight();
1205
1237
  } catch (exn) {
1206
- let seconds = Performance.secondsSince(timerRef);
1207
- Prometheus.SourceRequestCount.increment(name, chain, "eth_blockNumber");
1208
- Prometheus.SourceRequestCount.addSeconds(name, chain, "eth_blockNumber", seconds);
1238
+ recordRequest("eth_blockNumber", Performance.secondsSince(timerRef));
1209
1239
  throw exn;
1210
1240
  }
1211
- let seconds$1 = Performance.secondsSince(timerRef);
1212
- Prometheus.SourceRequestCount.increment(name, chain, "eth_blockNumber");
1213
- Prometheus.SourceRequestCount.addSeconds(name, chain, "eth_blockNumber", seconds$1);
1214
- return height;
1241
+ recordRequest("eth_blockNumber", Performance.secondsSince(timerRef));
1242
+ return {
1243
+ height: height,
1244
+ requestStats: drainRequestStats()
1245
+ };
1215
1246
  },
1216
1247
  getItemsOrThrow: getItemsOrThrow,
1217
1248
  createHeightSubscription: createHeightSubscription,
@@ -108,11 +108,6 @@ let subscribe = (~wsUrl, ~chainId, ~onHeight: int => unit): (unit => unit) => {
108
108
  | NewHead(blockNumber) =>
109
109
  errorCount := 0
110
110
  resetStaleTimeout()
111
- Prometheus.SourceRequestCount.increment(
112
- ~sourceName="WebSocket",
113
- ~chainId,
114
- ~method="eth_subscribe",
115
- )
116
111
  onHeight(blockNumber)
117
112
  | SubscriptionConfirmed(_) => resetStaleTimeout()
118
113
  | ErrorResponse =>
@@ -3,7 +3,6 @@
3
3
  import * as Rpc from "./Rpc.res.mjs";
4
4
  import * as Utils from "../Utils.res.mjs";
5
5
  import * as Logging from "../Logging.res.mjs";
6
- import * as Prometheus from "../Prometheus.res.mjs";
7
6
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
8
7
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
9
8
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
@@ -105,7 +104,6 @@ function subscribe(wsUrl, chainId, onHeight) {
105
104
  }
106
105
  errorCount.contents = 0;
107
106
  resetStaleTimeout();
108
- Prometheus.SourceRequestCount.increment("WebSocket", chainId, "eth_subscribe");
109
107
  return onHeight(blockNumber._0);
110
108
  } catch (raw_e) {
111
109
  let e = Primitive_exceptions.internalToException(raw_e);
@@ -12,11 +12,11 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
12
12
  poweredByHyperSync: false,
13
13
  pollingInterval: 0,
14
14
  getBlockHashes: (~blockNumbers as _, ~logger as _) => {
15
- Promise.resolve(Ok([]))
15
+ Promise.resolve({Source.result: Ok([]), requestStats: []})
16
16
  },
17
17
  getHeightOrThrow: () => {
18
18
  // Report at least height 1 so the engine doesn't treat 0 as "no blocks available"
19
- Promise.resolve(max(endBlock, 1))
19
+ Promise.resolve({Source.height: max(endBlock, 1), requestStats: []})
20
20
  },
21
21
  getItemsOrThrow: (
22
22
  ~fromBlock as _,
@@ -43,14 +43,16 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
43
43
  Source.knownHeight: reportedHeight,
44
44
  blockHashes: [],
45
45
  parsedQueueItems: result,
46
- // Simulate keeps the transaction inline on the payload; no store page.
46
+ // Simulate keeps the transaction and block inline on the payload; no store pages.
47
47
  transactionStore: None,
48
+ blockStore: None,
48
49
  fromBlockQueried: 0,
49
50
  latestFetchedBlockNumber: reportedHeight,
50
51
  latestFetchedBlockTimestamp: 0,
51
52
  stats: {
52
53
  totalTimeElapsed: 0.,
53
54
  },
55
+ requestStats: [],
54
56
  })
55
57
  },
56
58
  }