envio 3.3.0-alpha.7 → 3.3.0-alpha.9

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 (95) 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 +401 -171
  8. package/src/ChainState.res.mjs +270 -104
  9. package/src/ChainState.resi +19 -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 +82 -82
  14. package/src/CrossChainState.res.mjs +52 -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/EnvioGlobal.res +53 -0
  20. package/src/EnvioGlobal.res.mjs +31 -0
  21. package/src/EventConfigBuilder.res +117 -69
  22. package/src/EventConfigBuilder.res.mjs +71 -34
  23. package/src/EventProcessing.res +19 -15
  24. package/src/EventProcessing.res.mjs +13 -12
  25. package/src/FetchState.res +410 -185
  26. package/src/FetchState.res.mjs +268 -253
  27. package/src/HandlerLoader.res +8 -113
  28. package/src/HandlerLoader.res.mjs +2 -88
  29. package/src/HandlerRegister.res +518 -144
  30. package/src/HandlerRegister.res.mjs +285 -133
  31. package/src/HandlerRegister.resi +24 -8
  32. package/src/IndexerState.res +6 -3
  33. package/src/IndexerState.res.mjs +3 -3
  34. package/src/IndexerState.resi +1 -1
  35. package/src/IndexingAddresses.res +10 -7
  36. package/src/IndexingAddresses.res.mjs +8 -7
  37. package/src/IndexingAddresses.resi +3 -1
  38. package/src/Internal.res +104 -39
  39. package/src/Internal.res.mjs +11 -1
  40. package/src/LogSelection.res +102 -165
  41. package/src/LogSelection.res.mjs +101 -116
  42. package/src/Main.res +49 -164
  43. package/src/Main.res.mjs +39 -104
  44. package/src/Metrics.res +43 -2
  45. package/src/Metrics.res.mjs +39 -3
  46. package/src/Prometheus.res +0 -35
  47. package/src/Prometheus.res.mjs +33 -68
  48. package/src/RawEvent.res +7 -2
  49. package/src/RawEvent.res.mjs +4 -4
  50. package/src/RollbackCommit.res +4 -1
  51. package/src/RollbackCommit.res.mjs +3 -2
  52. package/src/SimulateItems.res +20 -7
  53. package/src/SimulateItems.res.mjs +7 -11
  54. package/src/TestIndexer.res +1 -1
  55. package/src/TestIndexer.res.mjs +1 -1
  56. package/src/sources/BlockStore.res +46 -0
  57. package/src/sources/BlockStore.res.mjs +24 -0
  58. package/src/sources/EventRouter.res +19 -12
  59. package/src/sources/EventRouter.res.mjs +7 -5
  60. package/src/sources/Evm.res +58 -5
  61. package/src/sources/Evm.res.mjs +44 -5
  62. package/src/sources/EvmChain.res +14 -18
  63. package/src/sources/EvmChain.res.mjs +12 -13
  64. package/src/sources/FieldMask.res +39 -0
  65. package/src/sources/FieldMask.res.mjs +42 -0
  66. package/src/sources/Fuel.res +8 -3
  67. package/src/sources/Fuel.res.mjs +5 -4
  68. package/src/sources/HyperFuelSource.res +31 -40
  69. package/src/sources/HyperFuelSource.res.mjs +52 -44
  70. package/src/sources/HyperSync.res +31 -9
  71. package/src/sources/HyperSync.res.mjs +47 -31
  72. package/src/sources/HyperSync.resi +10 -3
  73. package/src/sources/HyperSyncClient.res +15 -4
  74. package/src/sources/HyperSyncHeightStream.res +1 -8
  75. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  76. package/src/sources/HyperSyncSource.res +58 -90
  77. package/src/sources/HyperSyncSource.res.mjs +57 -66
  78. package/src/sources/RpcSource.res +118 -120
  79. package/src/sources/RpcSource.res.mjs +92 -74
  80. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  81. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  82. package/src/sources/SimulateSource.res +5 -3
  83. package/src/sources/SimulateSource.res.mjs +12 -4
  84. package/src/sources/Source.res +19 -5
  85. package/src/sources/SourceManager.res +60 -10
  86. package/src/sources/SourceManager.res.mjs +54 -8
  87. package/src/sources/SourceManager.resi +10 -0
  88. package/src/sources/Svm.res +14 -10
  89. package/src/sources/Svm.res.mjs +23 -6
  90. package/src/sources/SvmHyperSyncClient.res +5 -6
  91. package/src/sources/SvmHyperSyncSource.res +82 -41
  92. package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
  93. package/src/sources/TransactionStore.res +6 -107
  94. package/src/sources/TransactionStore.res.mjs +5 -86
  95. package/svm.schema.json +19 -0
@@ -13,7 +13,7 @@ type selectionConfig = {
13
13
  getRecieptsSelection: (
14
14
  ~addressesByContractName: dict<array<Address.t>>,
15
15
  ) => array<HyperFuelClient.QueryTypes.receiptSelection>,
16
- eventRouter: EventRouter.t<Internal.fuelEventConfig>,
16
+ eventRouter: EventRouter.t<Internal.fuelOnEventRegistration>,
17
17
  }
18
18
 
19
19
  let logDataReceiptTypeSelection: array<FuelSDK.receiptType> = [LogData]
@@ -127,39 +127,40 @@ let getSelectionConfig = (selection: FetchState.selection, ~chain) => {
127
127
 
128
128
  let contractNames = Utils.Set.make()
129
129
 
130
- selection.eventConfigs
131
- ->(Utils.magic: array<Internal.eventConfig> => array<Internal.fuelEventConfig>)
132
- ->Array.forEach(eventConfig => {
130
+ selection.onEventRegistrations->Array.forEach(reg => {
131
+ let eventConfig =
132
+ reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.fuelEventConfig)
133
133
  let contractName = eventConfig.contractName
134
- if !eventConfig.isWildcard {
134
+ let isWildcard = reg.isWildcard
135
+ if !isWildcard {
135
136
  let _ = contractNames->Utils.Set.add(contractName)
136
137
  }
137
138
  eventRouter->EventRouter.addOrThrow(
138
139
  eventConfig.id,
139
- eventConfig,
140
+ reg,
140
141
  ~contractName,
141
142
  ~eventName=eventConfig.name,
142
143
  ~chain,
143
- ~isWildcard=eventConfig.isWildcard,
144
+ ~isWildcard,
144
145
  )
145
146
 
146
- switch eventConfig {
147
- | {kind: Mint, isWildcard: true} => addNonLogDataWildcardReceiptTypes(Mint)
148
- | {kind: Mint} => addNonLogDataReceiptType(contractName, Mint)
149
- | {kind: Burn, isWildcard: true} => addNonLogDataWildcardReceiptTypes(Burn)
150
- | {kind: Burn} => addNonLogDataReceiptType(contractName, Burn)
151
- | {kind: Transfer, isWildcard: true} => {
147
+ switch (eventConfig.kind, isWildcard) {
148
+ | (Mint, true) => addNonLogDataWildcardReceiptTypes(Mint)
149
+ | (Mint, false) => addNonLogDataReceiptType(contractName, Mint)
150
+ | (Burn, true) => addNonLogDataWildcardReceiptTypes(Burn)
151
+ | (Burn, false) => addNonLogDataReceiptType(contractName, Burn)
152
+ | (Transfer, true) => {
152
153
  addNonLogDataWildcardReceiptTypes(Transfer)
153
154
  addNonLogDataWildcardReceiptTypes(TransferOut)
154
155
  }
155
- | {kind: Transfer} => {
156
+ | (Transfer, false) => {
156
157
  addNonLogDataReceiptType(contractName, Transfer)
157
158
  addNonLogDataReceiptType(contractName, TransferOut)
158
159
  }
159
- | {kind: Call, isWildcard: true} => addNonLogDataWildcardReceiptTypes(Call)
160
- | {kind: Call} =>
160
+ | (Call, true) => addNonLogDataWildcardReceiptTypes(Call)
161
+ | (Call, false) =>
161
162
  JsError.throwWithMessage("Call receipt indexing currently supported only in wildcard mode")
162
- | {kind: LogData({logId}), isWildcard} => {
163
+ | (LogData({logId}), _) => {
163
164
  let rb = logId->BigInt.fromStringOrThrow
164
165
  if isWildcard {
165
166
  wildcardLogDataRbs->Array.push(rb)->ignore
@@ -251,11 +252,6 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
251
252
  let startFetchingBatchTimeRef = Performance.now()
252
253
 
253
254
  //fetch batch
254
- Prometheus.SourceRequestCount.increment(
255
- ~sourceName=name,
256
- ~chainId=chain->ChainMap.Chain.toChainId,
257
- ~method="getLogs",
258
- )
259
255
  let pageUnsafe = try await HyperFuel.GetLogs.query(
260
256
  ~client,
261
257
  ~fromBlock,
@@ -307,6 +303,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
307
303
  }
308
304
 
309
305
  let pageFetchTime = startFetchingBatchTimeRef->Performance.secondsSince
306
+ let requestStats = [{Source.method: "getLogs", seconds: pageFetchTime}]
310
307
 
311
308
  //set height and next from block
312
309
  let knownHeight = pageUnsafe.archiveHeight
@@ -331,7 +328,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
331
328
  | Call(_) => callEventTag
332
329
  }
333
330
 
334
- let eventConfig = switch selectionConfig.eventRouter->EventRouter.get(
331
+ let onEventRegistration = switch selectionConfig.eventRouter->EventRouter.get(
335
332
  ~tag=eventId,
336
333
  ~contractNameByAddress,
337
334
  ~contractAddress,
@@ -352,9 +349,14 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
352
349
  ~logger,
353
350
  )
354
351
  }
355
- | Some(eventConfig) => eventConfig
352
+ | Some(onEventRegistration) => onEventRegistration
356
353
  }
357
354
 
355
+ let eventConfig =
356
+ onEventRegistration.eventConfig->(
357
+ Utils.magic: Internal.eventConfig => Internal.fuelEventConfig
358
+ )
359
+
358
360
  let params = switch (eventConfig, receipt) {
359
361
  | ({kind: LogData({decode})}, LogData({data})) =>
360
362
  try decode(data) catch {
@@ -408,11 +410,9 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
408
410
  }
409
411
 
410
412
  Internal.Event({
411
- eventConfig: (eventConfig :> Internal.eventConfig),
412
- timestamp: block.time,
413
+ onEventRegistration: (onEventRegistration :> Internal.onEventRegistration),
413
414
  chain,
414
415
  blockNumber: block.height,
415
- blockHash: block.id,
416
416
  logIndex: receiptIndex,
417
417
  // Fuel carries the transaction inline on the payload; the store key is
418
418
  // unused (Fuel identifies transactions by hash, kept on the payload).
@@ -459,13 +459,15 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
459
459
  {
460
460
  latestFetchedBlockTimestamp,
461
461
  parsedQueueItems,
462
- // Fuel keeps transaction on the payload; no store page.
462
+ // Fuel keeps transaction and block on the payload; no store pages.
463
463
  transactionStore: None,
464
+ blockStore: None,
464
465
  latestFetchedBlockNumber: heighestBlockQueried,
465
466
  stats,
466
467
  knownHeight,
467
468
  blockHashes,
468
469
  fromBlockQueried: fromBlock,
470
+ requestStats,
469
471
  }
470
472
  }
471
473
 
@@ -493,18 +495,7 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
493
495
  }
494
496
  }
495
497
  let seconds = timerRef->Performance.secondsSince
496
- Prometheus.SourceRequestCount.increment(
497
- ~sourceName=name,
498
- ~chainId=chain->ChainMap.Chain.toChainId,
499
- ~method="getHeight",
500
- )
501
- Prometheus.SourceRequestCount.addSeconds(
502
- ~sourceName=name,
503
- ~chainId=chain->ChainMap.Chain.toChainId,
504
- ~method="getHeight",
505
- ~seconds,
506
- )
507
- height
498
+ {height, requestStats: [{method: "getHeight", seconds}]}
508
499
  },
509
500
  getItemsOrThrow,
510
501
  }
@@ -3,7 +3,6 @@
3
3
  import * as Source from "./Source.res.mjs";
4
4
  import * as Logging from "../Logging.res.mjs";
5
5
  import * as HyperFuel from "./HyperFuel.res.mjs";
6
- import * as Prometheus from "../Prometheus.res.mjs";
7
6
  import * as EventRouter from "./EventRouter.res.mjs";
8
7
  import * as Performance from "../bindings/Performance.res.mjs";
9
8
  import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
@@ -101,41 +100,43 @@ function getSelectionConfig(selection, chain) {
101
100
  }
102
101
  };
103
102
  let contractNames = new Set();
104
- selection.eventConfigs.forEach(eventConfig => {
103
+ selection.onEventRegistrations.forEach(reg => {
104
+ let eventConfig = reg.eventConfig;
105
105
  let contractName = eventConfig.contractName;
106
- if (!eventConfig.isWildcard) {
106
+ let isWildcard = reg.isWildcard;
107
+ if (!isWildcard) {
107
108
  contractNames.add(contractName);
108
109
  }
109
- EventRouter.addOrThrow(eventRouter, eventConfig.id, eventConfig, contractName, eventConfig.isWildcard, eventConfig.name, chain);
110
- let isWildcard = eventConfig.isWildcard;
111
- if (isWildcard) {
112
- let tmp = eventConfig.kind;
113
- if (typeof tmp !== "object") {
114
- switch (tmp) {
115
- case "Mint" :
116
- return addNonLogDataWildcardReceiptTypes(11);
117
- case "Burn" :
118
- return addNonLogDataWildcardReceiptTypes(12);
119
- case "Transfer" :
120
- addNonLogDataWildcardReceiptTypes(7);
121
- return addNonLogDataWildcardReceiptTypes(8);
122
- case "Call" :
123
- return addNonLogDataWildcardReceiptTypes(0);
124
- }
125
- }
126
- }
110
+ EventRouter.addOrThrow(eventRouter, eventConfig.id, reg, contractName, isWildcard, eventConfig.name, chain);
127
111
  let match = eventConfig.kind;
128
112
  if (typeof match !== "object") {
129
113
  switch (match) {
130
114
  case "Mint" :
131
- return addNonLogDataReceiptType(contractName, 11);
115
+ if (isWildcard) {
116
+ return addNonLogDataWildcardReceiptTypes(11);
117
+ } else {
118
+ return addNonLogDataReceiptType(contractName, 11);
119
+ }
132
120
  case "Burn" :
133
- return addNonLogDataReceiptType(contractName, 12);
121
+ if (isWildcard) {
122
+ return addNonLogDataWildcardReceiptTypes(12);
123
+ } else {
124
+ return addNonLogDataReceiptType(contractName, 12);
125
+ }
134
126
  case "Transfer" :
135
- addNonLogDataReceiptType(contractName, 7);
136
- return addNonLogDataReceiptType(contractName, 8);
127
+ if (isWildcard) {
128
+ addNonLogDataWildcardReceiptTypes(7);
129
+ return addNonLogDataWildcardReceiptTypes(8);
130
+ } else {
131
+ addNonLogDataReceiptType(contractName, 7);
132
+ return addNonLogDataReceiptType(contractName, 8);
133
+ }
137
134
  case "Call" :
138
- return Stdlib_JsError.throwWithMessage("Call receipt indexing currently supported only in wildcard mode");
135
+ if (isWildcard) {
136
+ return addNonLogDataWildcardReceiptTypes(0);
137
+ } else {
138
+ return Stdlib_JsError.throwWithMessage("Call receipt indexing currently supported only in wildcard mode");
139
+ }
139
140
  }
140
141
  } else {
141
142
  let rb = BigInt(match.logId);
@@ -181,7 +182,6 @@ function memoGetSelectionConfig(chain) {
181
182
  function make(param) {
182
183
  let apiToken = param.apiToken;
183
184
  let chain = param.chain;
184
- let name = "HyperFuel";
185
185
  let apiToken$1 = apiToken !== undefined ? apiToken : Stdlib_JsError.throwWithMessage(`An Envio API token is required for using HyperFuel as a data-source.
186
186
  Set the ENVIO_API_TOKEN environment variable in your .env file.
187
187
  Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
@@ -201,7 +201,6 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
201
201
  let selectionConfig = getSelectionConfig(selection);
202
202
  let recieptsSelection = selectionConfig.getRecieptsSelection(addressesByContractName);
203
203
  let startFetchingBatchTimeRef = Performance.now();
204
- Prometheus.SourceRequestCount.increment(name, chain, "getLogs");
205
204
  let pageUnsafe;
206
205
  try {
207
206
  pageUnsafe = await HyperFuel.GetLogs.query(client, fromBlock, toBlock, recieptsSelection);
@@ -250,6 +249,10 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
250
249
  };
251
250
  }
252
251
  let pageFetchTime = Performance.secondsSince(startFetchingBatchTimeRef);
252
+ let requestStats = [{
253
+ method: "getLogs",
254
+ seconds: pageFetchTime
255
+ }];
253
256
  let knownHeight$1 = pageUnsafe.archiveHeight;
254
257
  let heighestBlockQueried = pageUnsafe.nextBlock - 1 | 0;
255
258
  let parsingTimeRef = Performance.now();
@@ -277,10 +280,10 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
277
280
  eventId = burnEventTag;
278
281
  break;
279
282
  }
280
- let eventConfig = EventRouter.get(selectionConfig.eventRouter, eventId, contractAddress, contractNameByAddress);
281
- let eventConfig$1;
282
- if (eventConfig !== undefined) {
283
- eventConfig$1 = eventConfig;
283
+ let onEventRegistration = EventRouter.get(selectionConfig.eventRouter, eventId, contractAddress, contractNameByAddress);
284
+ let onEventRegistration$1;
285
+ if (onEventRegistration !== undefined) {
286
+ onEventRegistration$1 = onEventRegistration;
284
287
  } else {
285
288
  let logger$1 = Logging.createChildFrom(logger, {
286
289
  chainId: chain,
@@ -289,11 +292,12 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
289
292
  contractAddress: contractAddress,
290
293
  eventId: eventId
291
294
  });
292
- eventConfig$1 = ErrorHandling.mkLogAndRaise(logger$1, "Failed to route registered event", {
295
+ onEventRegistration$1 = ErrorHandling.mkLogAndRaise(logger$1, "Failed to route registered event", {
293
296
  RE_EXN_ID: EventRoutingFailed
294
297
  });
295
298
  }
296
- let match = eventConfig$1.kind;
299
+ let eventConfig = onEventRegistration$1.eventConfig;
300
+ let match = eventConfig.kind;
297
301
  let params;
298
302
  let exit = 0;
299
303
  if (typeof match !== "object" || receipt.receiptType !== 6) {
@@ -349,16 +353,14 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
349
353
  }
350
354
  return {
351
355
  kind: 0,
352
- eventConfig: eventConfig$1,
353
- timestamp: block.time,
356
+ onEventRegistration: onEventRegistration$1,
354
357
  chain: chain,
355
358
  blockNumber: block.height,
356
- blockHash: block.id,
357
359
  logIndex: receiptIndex,
358
360
  transactionIndex: 0,
359
361
  payload: {
360
- contractName: eventConfig$1.contractName,
361
- eventName: eventConfig$1.name,
362
+ contractName: eventConfig.contractName,
363
+ eventName: eventConfig.name,
362
364
  params: params,
363
365
  chainId: chain,
364
366
  srcAddress: contractAddress,
@@ -399,15 +401,17 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
399
401
  blockHashes: blockHashes,
400
402
  parsedQueueItems: parsedQueueItems,
401
403
  transactionStore: undefined,
404
+ blockStore: undefined,
402
405
  fromBlockQueried: fromBlock,
403
406
  latestFetchedBlockNumber: heighestBlockQueried,
404
407
  latestFetchedBlockTimestamp: latestFetchedBlockTimestamp,
405
- stats: stats
408
+ stats: stats,
409
+ requestStats: requestStats
406
410
  };
407
411
  };
408
412
  let getBlockHashes = (param, param$1) => Stdlib_JsError.throwWithMessage("HyperFuel does not support getting block hashes");
409
413
  return {
410
- name: name,
414
+ name: "HyperFuel",
411
415
  sourceFor: "Sync",
412
416
  chain: chain,
413
417
  poweredByHyperSync: true,
@@ -447,9 +451,13 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`);
447
451
  }
448
452
  }
449
453
  let seconds = Performance.secondsSince(timerRef);
450
- Prometheus.SourceRequestCount.increment(name, chain, "getHeight");
451
- Prometheus.SourceRequestCount.addSeconds(name, chain, "getHeight", seconds);
452
- return height;
454
+ return {
455
+ height: height,
456
+ requestStats: [{
457
+ method: "getHeight",
458
+ seconds: seconds
459
+ }]
460
+ };
453
461
  },
454
462
  getItemsOrThrow: getItemsOrThrow
455
463
  };
@@ -16,13 +16,15 @@ let reraisIfRateLimited = exn =>
16
16
 
17
17
  type logsQueryPage = {
18
18
  items: array<HyperSyncClient.EventItems.item>,
19
- // Blocks referenced by `items`, deduplicated by block number.
20
- blocks: array<HyperSyncClient.ResponseTypes.block>,
19
+ // Block headers referenced by `items`, deduplicated by block number.
20
+ blocks: array<HyperSyncClient.EventItems.blockHeader>,
21
21
  nextBlock: int,
22
22
  archiveHeight: int,
23
23
  rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
24
24
  // Page store owning this page's raw transactions.
25
25
  transactionStore: TransactionStore.t,
26
+ // Page store owning this page's raw blocks.
27
+ blockStore: BlockStore.t,
26
28
  }
27
29
 
28
30
  type missingParams = {
@@ -129,7 +131,7 @@ module GetLogs = {
129
131
  ~maxNumLogs,
130
132
  )
131
133
 
132
- let (res, transactionStore) = switch await client.getEventItems(~query) {
134
+ let (res, transactionStore, blockStore) = switch await client.getEventItems(~query) {
133
135
  | res => res
134
136
  | exception exn =>
135
137
  reraisIfRateLimited(exn)
@@ -150,6 +152,7 @@ module GetLogs = {
150
152
  archiveHeight: res.archiveHeight->Option.getOr(0), //Archive Height is only None if height is 0
151
153
  rollbackGuard: res.rollbackGuard,
152
154
  transactionStore,
155
+ blockStore,
153
156
  }
154
157
  }
155
158
  }
@@ -206,6 +209,7 @@ module BlockData = {
206
209
  ~sourceName,
207
210
  ~chainId,
208
211
  ~logger,
212
+ ~requestStats: array<Source.requestStat>,
209
213
  ): queryResponse<array<ReorgDetection.blockDataWithTimestamp>> => {
210
214
  let body = makeRequestBody(~fromBlock, ~toBlock)
211
215
 
@@ -218,7 +222,7 @@ module BlockData = {
218
222
  },
219
223
  )
220
224
 
221
- Prometheus.SourceRequestCount.increment(~sourceName, ~chainId, ~method="getBlockHashes")
225
+ let timerRef = Performance.now()
222
226
  let maybeSuccessfulRes = switch await client.get(~query=body) {
223
227
  | exception exn =>
224
228
  reraisIfRateLimited(exn)
@@ -226,6 +230,9 @@ module BlockData = {
226
230
  | res if res.nextBlock <= fromBlock => None
227
231
  | res => Some(res)
228
232
  }
233
+ requestStats
234
+ ->Array.push({Source.method: "getBlockHashes", seconds: timerRef->Performance.secondsSince})
235
+ ->ignore
229
236
 
230
237
  // If the block is not found, retry the query. This can occur since replicas of hypersync might not have caught up yet
231
238
  switch maybeSuccessfulRes {
@@ -235,7 +242,15 @@ module BlockData = {
235
242
  `Block #${fromBlock->Int.toString} not found in HyperSync. HyperSync has multiple instances and it's possible that they drift independently slightly from the head. Indexing should continue correctly after retrying the query in ${delayMilliseconds->Int.toString}ms.`,
236
243
  )
237
244
  await Time.resolvePromiseAfterDelay(~delayMilliseconds)
238
- await queryBlockData(~client, ~fromBlock, ~toBlock, ~sourceName, ~chainId, ~logger)
245
+ await queryBlockData(
246
+ ~client,
247
+ ~fromBlock,
248
+ ~toBlock,
249
+ ~sourceName,
250
+ ~chainId,
251
+ ~logger,
252
+ ~requestStats,
253
+ )
239
254
  }
240
255
  | Some(res) =>
241
256
  switch res->convertResponse {
@@ -248,6 +263,7 @@ module BlockData = {
248
263
  ~sourceName,
249
264
  ~chainId,
250
265
  ~logger,
266
+ ~requestStats,
251
267
  )
252
268
  restRes->Result.map(rest => datas->Array.concat(rest))
253
269
  }
@@ -262,8 +278,9 @@ module BlockData = {
262
278
  ~sourceName,
263
279
  ~chainId,
264
280
  ~logger,
265
- ) => {
266
- switch blockNumbers->Array.get(0) {
281
+ ): (queryResponse<array<ReorgDetection.blockDataWithTimestamp>>, array<Source.requestStat>) => {
282
+ let requestStats = []
283
+ let result = switch blockNumbers->Array.get(0) {
267
284
  | None => Ok([])
268
285
  | Some(firstBlock) => {
269
286
  let fromBlock = ref(firstBlock)
@@ -291,6 +308,7 @@ module BlockData = {
291
308
  ~sourceName,
292
309
  ~chainId,
293
310
  ~logger,
311
+ ~requestStats,
294
312
  )
295
313
  let filtered = res->Result.map(datas => {
296
314
  datas->Array.filter(data => set->Utils.Set.delete(data.blockNumber))
@@ -305,10 +323,12 @@ module BlockData = {
305
323
  filtered
306
324
  }
307
325
  }
326
+ (result, requestStats)
308
327
  }
309
328
  }
310
329
 
311
- let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
330
+ let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) => {
331
+ let requestStats = []
312
332
  BlockData.queryBlockData(
313
333
  ~client,
314
334
  ~fromBlock=blockNumber,
@@ -316,5 +336,7 @@ let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
316
336
  ~sourceName,
317
337
  ~chainId,
318
338
  ~logger,
319
- )->Promise.thenResolve(res => res->Result.map(res => res->Array.get(0)))
339
+ ~requestStats,
340
+ )->Promise.thenResolve(res => (res->Result.map(res => res->Array.get(0)), requestStats))
341
+ }
320
342
  let queryBlockDataMulti = BlockData.queryBlockDataMulti
@@ -4,8 +4,8 @@ import * as Time from "../Time.res.mjs";
4
4
  import * as Utils from "../Utils.res.mjs";
5
5
  import * as Source from "./Source.res.mjs";
6
6
  import * as Logging from "../Logging.res.mjs";
7
- import * as Prometheus from "../Prometheus.res.mjs";
8
7
  import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
8
+ import * as Performance from "../bindings/Performance.res.mjs";
9
9
  import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
10
10
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
11
11
  import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
@@ -135,7 +135,8 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection,
135
135
  nextBlock: res.nextBlock,
136
136
  archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0),
137
137
  rollbackGuard: res.rollbackGuard,
138
- transactionStore: match[1]
138
+ transactionStore: match[1],
139
+ blockStore: match[2]
139
140
  };
140
141
  }
141
142
 
@@ -191,14 +192,14 @@ function convertResponse(res) {
191
192
  }));
192
193
  }
193
194
 
194
- async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger) {
195
+ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats) {
195
196
  let body = makeRequestBody$1(fromBlock, toBlock);
196
197
  let logger$1 = Logging.createChildFrom(logger, {
197
198
  logType: "HyperSync get block hash query",
198
199
  fromBlock: fromBlock,
199
200
  toBlock: toBlock
200
201
  });
201
- Prometheus.SourceRequestCount.increment(sourceName, chainId, "getBlockHashes");
202
+ let timerRef = Performance.now();
202
203
  let maybeSuccessfulRes;
203
204
  let exit = 0;
204
205
  let res;
@@ -213,6 +214,10 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
213
214
  if (exit === 1) {
214
215
  maybeSuccessfulRes = res.nextBlock <= fromBlock ? undefined : res;
215
216
  }
217
+ requestStats.push({
218
+ method: "getBlockHashes",
219
+ seconds: Performance.secondsSince(timerRef)
220
+ });
216
221
  if (maybeSuccessfulRes !== undefined) {
217
222
  let err = convertResponse(maybeSuccessfulRes);
218
223
  if (err.TAG !== "Ok") {
@@ -222,48 +227,59 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
222
227
  return err;
223
228
  }
224
229
  let datas = err._0;
225
- let restRes = await queryBlockData(client, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1);
230
+ let restRes = await queryBlockData(client, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1, requestStats);
226
231
  return Stdlib_Result.map(restRes, rest => datas.concat(rest));
227
232
  }
228
233
  Logging.childInfo(logger$1, `Block #` + fromBlock.toString() + ` not found in HyperSync. HyperSync has multiple instances and it's possible that they drift independently slightly from the head. Indexing should continue correctly after retrying the query in ` + (100).toString() + `ms.`);
229
234
  await Time.resolvePromiseAfterDelay(100);
230
- return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1);
235
+ return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1, requestStats);
231
236
  }
232
237
 
233
238
  async function queryBlockDataMulti(client, blockNumbers, sourceName, chainId, logger) {
239
+ let requestStats = [];
234
240
  let firstBlock = blockNumbers[0];
235
- if (firstBlock === undefined) {
236
- return {
241
+ let result;
242
+ if (firstBlock !== undefined) {
243
+ let fromBlock = firstBlock;
244
+ let toBlock = firstBlock;
245
+ let set = new Set();
246
+ for (let idx = 0, idx_finish = blockNumbers.length; idx < idx_finish; ++idx) {
247
+ let blockNumber = blockNumbers[idx];
248
+ if (blockNumber < fromBlock) {
249
+ fromBlock = blockNumber;
250
+ }
251
+ if (blockNumber > toBlock) {
252
+ toBlock = blockNumber;
253
+ }
254
+ set.add(blockNumber);
255
+ }
256
+ if ((toBlock - fromBlock | 0) > 1000) {
257
+ Stdlib_JsError.throwWithMessage(`Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: ` + fromBlock.toString() + `-` + toBlock.toString());
258
+ }
259
+ let res = await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats);
260
+ let filtered = Stdlib_Result.map(res, datas => datas.filter(data => set.delete(data.blockNumber)));
261
+ if (set.size > 0) {
262
+ Stdlib_JsError.throwWithMessage(`Invalid response. Failed to get block data for block numbers: ` + Array.from(set).join(", "));
263
+ }
264
+ result = filtered;
265
+ } else {
266
+ result = {
237
267
  TAG: "Ok",
238
268
  _0: []
239
269
  };
240
270
  }
241
- let fromBlock = firstBlock;
242
- let toBlock = firstBlock;
243
- let set = new Set();
244
- for (let idx = 0, idx_finish = blockNumbers.length; idx < idx_finish; ++idx) {
245
- let blockNumber = blockNumbers[idx];
246
- if (blockNumber < fromBlock) {
247
- fromBlock = blockNumber;
248
- }
249
- if (blockNumber > toBlock) {
250
- toBlock = blockNumber;
251
- }
252
- set.add(blockNumber);
253
- }
254
- if ((toBlock - fromBlock | 0) > 1000) {
255
- Stdlib_JsError.throwWithMessage(`Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: ` + fromBlock.toString() + `-` + toBlock.toString());
256
- }
257
- let res = await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger);
258
- let filtered = Stdlib_Result.map(res, datas => datas.filter(data => set.delete(data.blockNumber)));
259
- if (set.size > 0) {
260
- Stdlib_JsError.throwWithMessage(`Invalid response. Failed to get block data for block numbers: ` + Array.from(set).join(", "));
261
- }
262
- return filtered;
271
+ return [
272
+ result,
273
+ requestStats
274
+ ];
263
275
  }
264
276
 
265
277
  function queryBlockData$1(client, blockNumber, sourceName, chainId, logger) {
266
- return queryBlockData(client, blockNumber, blockNumber, sourceName, chainId, logger).then(res => Stdlib_Result.map(res, res => res[0]));
278
+ let requestStats = [];
279
+ return queryBlockData(client, blockNumber, blockNumber, sourceName, chainId, logger, requestStats).then(res => [
280
+ Stdlib_Result.map(res, res => res[0]),
281
+ requestStats
282
+ ]);
267
283
  }
268
284
 
269
285
  let GetLogs = {
@@ -1,10 +1,11 @@
1
1
  type logsQueryPage = {
2
2
  items: array<HyperSyncClient.EventItems.item>,
3
- blocks: array<HyperSyncClient.ResponseTypes.block>,
3
+ blocks: array<HyperSyncClient.EventItems.blockHeader>,
4
4
  nextBlock: int,
5
5
  archiveHeight: int,
6
6
  rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
7
7
  transactionStore: TransactionStore.t,
8
+ blockStore: BlockStore.t,
8
9
  }
9
10
 
10
11
  type missingParams = {
@@ -43,7 +44,10 @@ let queryBlockData: (
43
44
  ~sourceName: string,
44
45
  ~chainId: int,
45
46
  ~logger: Pino.t,
46
- ) => promise<queryResponse<option<ReorgDetection.blockDataWithTimestamp>>>
47
+ ) => promise<(
48
+ queryResponse<option<ReorgDetection.blockDataWithTimestamp>>,
49
+ array<Source.requestStat>,
50
+ )>
47
51
 
48
52
  let queryBlockDataMulti: (
49
53
  ~client: HyperSyncClient.t,
@@ -51,6 +55,9 @@ let queryBlockDataMulti: (
51
55
  ~sourceName: string,
52
56
  ~chainId: int,
53
57
  ~logger: Pino.t,
54
- ) => promise<queryResponse<array<ReorgDetection.blockDataWithTimestamp>>>
58
+ ) => promise<(
59
+ queryResponse<array<ReorgDetection.blockDataWithTimestamp>>,
60
+ array<Source.requestStat>,
61
+ )>
55
62
 
56
63
  let mapExn: queryResponse<'a> => result<'a, exn>
@@ -254,11 +254,19 @@ module EventItems = {
254
254
  params: Nullable.t<dict<Internal.eventParams>>,
255
255
  }
256
256
 
257
+ // The always-needed block fields, one per block number. The block's remaining
258
+ // fields live raw in the block store and are materialised on demand.
259
+ type blockHeader = {
260
+ number: int,
261
+ timestamp: int,
262
+ hash: string,
263
+ }
264
+
257
265
  type response = {
258
266
  archiveHeight: option<int>,
259
267
  nextBlock: int,
260
- // One entry per block number referenced by `items`.
261
- blocks: array<ResponseTypes.block>,
268
+ // One header per block number referenced by `items`.
269
+ blocks: array<blockHeader>,
262
270
  items: array<item>,
263
271
  rollbackGuard: option<ResponseTypes.rollbackGuard>,
264
272
  }
@@ -266,8 +274,11 @@ module EventItems = {
266
274
 
267
275
  type t = {
268
276
  get: (~query: query) => promise<queryResponse>,
269
- // Returns the response plus a page store owning this page's raw transactions.
270
- getEventItems: (~query: query) => promise<(EventItems.response, TransactionStore.t)>,
277
+ // Returns the response plus page stores owning this page's raw transactions
278
+ // and blocks.
279
+ getEventItems: (
280
+ ~query: query,
281
+ ) => promise<(EventItems.response, TransactionStore.t, BlockStore.t)>,
271
282
  getHeight: unit => promise<int>,
272
283
  }
273
284