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
@@ -2,7 +2,6 @@
2
2
 
3
3
  import * as Utils from "../Utils.res.mjs";
4
4
  import * as Logging from "../Logging.res.mjs";
5
- import * as Prometheus from "../Prometheus.res.mjs";
6
5
  import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
7
6
  import * as Eventsource from "eventsource";
8
7
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
@@ -83,7 +82,6 @@ function subscribe(hyperSyncUrl, apiToken, chainId, onHeight) {
83
82
  es$1.addEventListener("height", event => {
84
83
  let height = Stdlib_Int.fromString(event.data, undefined);
85
84
  if (height !== undefined) {
86
- Prometheus.SourceRequestCount.increment("HyperSync", chainId, "heightStream");
87
85
  updateTimeoutId();
88
86
  return onHeight(height);
89
87
  } else {
@@ -1,132 +1,5 @@
1
1
  open Source
2
2
 
3
- type selectionConfig = {
4
- getLogSelectionOrThrow: (
5
- ~addressesByContractName: dict<array<Address.t>>,
6
- ) => array<LogSelection.t>,
7
- fieldSelection: HyperSyncClient.QueryTypes.fieldSelection,
8
- }
9
-
10
- let getSelectionConfig = (selection: FetchState.selection, ~chain) => {
11
- let capitalizedBlockFields = Utils.Set.make()
12
- let capitalizedTransactionFields = Utils.Set.make()
13
-
14
- let staticTopicSelectionsByContract = Dict.make()
15
- let dynamicEventFiltersByContract = Dict.make()
16
- let dynamicWildcardEventFiltersByContract = Dict.make()
17
- let noAddressesTopicSelections = []
18
- let contractNames = Utils.Set.make()
19
-
20
- selection.eventConfigs
21
- ->(Utils.magic: array<Internal.eventConfig> => array<Internal.evmEventConfig>)
22
- ->Array.forEach(({
23
- dependsOnAddresses,
24
- contractName,
25
- getEventFiltersOrThrow,
26
- selectedBlockFields,
27
- selectedTransactionFields,
28
- isWildcard,
29
- }) => {
30
- selectedBlockFields
31
- ->Utils.Set.toArray
32
- ->Array.forEach(name =>
33
- capitalizedBlockFields
34
- ->Utils.Set.add((name :> string)->Utils.String.capitalize)
35
- ->ignore
36
- )
37
- selectedTransactionFields
38
- ->Utils.Set.toArray
39
- ->Array.forEach(name =>
40
- capitalizedTransactionFields
41
- ->Utils.Set.add((name :> string)->Utils.String.capitalize)
42
- ->ignore
43
- )
44
-
45
- let eventFilters = getEventFiltersOrThrow(chain)
46
- if dependsOnAddresses {
47
- let _ = contractNames->Utils.Set.add(contractName)
48
- switch eventFilters {
49
- | Static(topicSelections) =>
50
- staticTopicSelectionsByContract->Utils.Dict.pushMany(contractName, topicSelections)
51
- | Dynamic(fn) =>
52
- (
53
- isWildcard ? dynamicWildcardEventFiltersByContract : dynamicEventFiltersByContract
54
- )->Utils.Dict.push(contractName, fn)
55
- }
56
- } else {
57
- noAddressesTopicSelections
58
- ->Array.pushMany(
59
- switch eventFilters {
60
- | Static(s) => s
61
- | Dynamic(fn) => fn([])
62
- },
63
- )
64
- ->ignore
65
- }
66
- })
67
-
68
- let fieldSelection: HyperSyncClient.QueryTypes.fieldSelection = {
69
- log: [Address, Data, LogIndex, Topic0, Topic1, Topic2, Topic3],
70
- block: capitalizedBlockFields
71
- ->Utils.Set.toArray
72
- ->(Utils.magic: array<string> => array<HyperSyncClient.QueryTypes.blockField>),
73
- transaction: capitalizedTransactionFields
74
- ->Utils.Set.toArray
75
- ->(Utils.magic: array<string> => array<HyperSyncClient.QueryTypes.transactionField>),
76
- }
77
-
78
- let noAddressesLogSelection = LogSelection.make(
79
- ~addresses=[],
80
- ~topicSelections=noAddressesTopicSelections,
81
- )
82
-
83
- let getLogSelectionOrThrow = (~addressesByContractName): array<LogSelection.t> => {
84
- let logSelections = []
85
- if noAddressesLogSelection.topicSelections->Utils.Array.isEmpty->not {
86
- logSelections->Array.push(noAddressesLogSelection)
87
- }
88
- contractNames->Utils.Set.forEach(contractName => {
89
- switch addressesByContractName->Utils.Dict.dangerouslyGetNonOption(contractName) {
90
- | None
91
- | Some([]) => ()
92
- | Some(addresses) =>
93
- switch staticTopicSelectionsByContract->Utils.Dict.dangerouslyGetNonOption(contractName) {
94
- | None => ()
95
- | Some(topicSelections) =>
96
- logSelections->Array.push(LogSelection.make(~addresses, ~topicSelections))
97
- }
98
- switch dynamicEventFiltersByContract->Utils.Dict.dangerouslyGetNonOption(contractName) {
99
- | None => ()
100
- | Some(fns) =>
101
- logSelections->Array.push(
102
- LogSelection.make(~addresses, ~topicSelections=fns->Array.flatMap(fn => fn(addresses))),
103
- )
104
- }
105
- switch dynamicWildcardEventFiltersByContract->Utils.Dict.dangerouslyGetNonOption(
106
- contractName,
107
- ) {
108
- | None => ()
109
- | Some(fns) =>
110
- logSelections->Array.push(
111
- LogSelection.make(
112
- ~addresses=[],
113
- ~topicSelections=fns->Array.flatMap(fn => fn(addresses)),
114
- ),
115
- )
116
- }
117
- }
118
- })
119
- logSelections
120
- }
121
-
122
- {
123
- getLogSelectionOrThrow,
124
- fieldSelection,
125
- }
126
- }
127
-
128
- let memoGetSelectionConfig = (~chain) =>
129
- Utils.WeakMap.memoize(selection => selection->getSelectionConfig(~chain))
130
3
 
131
4
  // Surfaced by HyperSyncClient.getHeight (Rust) when HyperSync rejects the API
132
5
  // token. The corrupted-token test feeds the real server error through this
@@ -136,8 +9,8 @@ let isUnauthorizedError = (message: string) => message->String.includes("401 Una
136
9
  type options = {
137
10
  chain: ChainMap.Chain.t,
138
11
  endpointUrl: string,
139
- allEventParams: array<HyperSyncClient.Decoder.eventParamsInput>,
140
- eventRouter: EventRouter.t<Internal.evmEventConfig>,
12
+ // The chain's registrations, indexed by their sequential `index`.
13
+ onEventRegistrations: array<Internal.evmOnEventRegistration>,
141
14
  apiToken: option<string>,
142
15
  clientTimeoutMillis: int,
143
16
  lowercaseAddresses: bool,
@@ -150,8 +23,7 @@ let make = (
150
23
  {
151
24
  chain,
152
25
  endpointUrl,
153
- allEventParams,
154
- eventRouter,
26
+ onEventRegistrations,
155
27
  apiToken,
156
28
  clientTimeoutMillis,
157
29
  lowercaseAddresses,
@@ -162,8 +34,6 @@ let make = (
162
34
  ): t => {
163
35
  let name = "HyperSync"
164
36
 
165
- let getSelectionConfig = memoGetSelectionConfig(~chain)
166
-
167
37
  let apiToken = switch apiToken {
168
38
  | Some(token) => token
169
39
  | None =>
@@ -176,7 +46,9 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
176
46
  ~url=endpointUrl,
177
47
  ~apiToken,
178
48
  ~httpReqTimeoutMillis=clientTimeoutMillis,
179
- ~eventParams=allEventParams,
49
+ ~eventRegistrations=HyperSyncClient.Registration.fromOnEventRegistrations(
50
+ onEventRegistrations,
51
+ ),
180
52
  ~enableChecksumAddresses=!lowercaseAddresses,
181
53
  ~serializationFormat,
182
54
  ~enableQueryCaching,
@@ -189,32 +61,25 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
189
61
  )
190
62
  }
191
63
 
192
- exception UndefinedValue
193
-
194
64
  let makeEventBatchQueueItem = (
195
65
  item: HyperSyncClient.EventItems.item,
196
- ~params: Internal.eventParams,
197
- ~eventConfig: Internal.evmEventConfig,
66
+ ~onEventRegistration: Internal.evmOnEventRegistration,
198
67
  ): Internal.item => {
199
- let {block, transaction, logIndex, srcAddress} = item
200
- let chainId = chain->ChainMap.Chain.toChainId
68
+ let {transactionIndex, logIndex, srcAddress} = item
201
69
 
202
70
  Internal.Event({
203
- eventConfig: (eventConfig :> Internal.eventConfig),
204
- timestamp: block.timestamp->Option.getUnsafe,
71
+ onEventRegistration: (onEventRegistration :> Internal.onEventRegistration),
205
72
  chain,
206
- blockNumber: block.number->Option.getUnsafe,
207
- blockHash: block.hash->Option.getUnsafe,
73
+ blockNumber: item.blockNumber,
208
74
  logIndex,
75
+ transactionIndex,
76
+ // `block` and `transaction` are omitted; they're materialised from the
77
+ // per-chain stores onto the payload at batch prep.
209
78
  payload: {
210
- contractName: eventConfig.contractName,
211
- eventName: eventConfig.name,
212
- chainId,
213
- params,
214
- transaction: transaction->(
215
- Utils.magic: HyperSyncClient.ResponseTypes.transaction => Internal.eventTransaction
216
- ),
217
- block: block->(Utils.magic: HyperSyncClient.ResponseTypes.block => Internal.eventBlock),
79
+ contractName: onEventRegistration.eventConfig.contractName,
80
+ eventName: onEventRegistration.eventConfig.name,
81
+ chainId: chain->ChainMap.Chain.toChainId,
82
+ params: item.params,
218
83
  srcAddress,
219
84
  logIndex,
220
85
  }->Evm.fromPayload,
@@ -225,36 +90,26 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
225
90
  ~fromBlock,
226
91
  ~toBlock,
227
92
  ~addressesByContractName,
228
- ~indexingAddresses,
93
+ ~contractNameByAddress as _,
229
94
  ~knownHeight,
230
95
  ~partitionId as _,
231
- ~selection,
96
+ ~selection: FetchState.selection,
97
+ ~itemsTarget,
232
98
  ~retry,
233
- ~logger,
99
+ ~logger as _,
234
100
  ) => {
235
- let totalTimeRef = Hrtime.makeTimer()
101
+ let totalTimeRef = Performance.now()
236
102
 
237
- let selectionConfig = selection->getSelectionConfig
238
-
239
- let logSelections = try selectionConfig.getLogSelectionOrThrow(~addressesByContractName) catch {
240
- | exn =>
241
- exn->ErrorHandling.mkLogAndRaise(~logger, ~msg="Failed getting log selection for the query")
242
- }
243
-
244
- let startFetchingBatchTimeRef = Hrtime.makeTimer()
103
+ let startFetchingBatchTimeRef = Performance.now()
245
104
 
246
105
  //fetch batch
247
- Prometheus.SourceRequestCount.increment(
248
- ~sourceName=name,
249
- ~chainId=chain->ChainMap.Chain.toChainId,
250
- ~method="getLogs",
251
- )
252
106
  let pageUnsafe = try await HyperSync.GetLogs.query(
253
107
  ~client,
254
108
  ~fromBlock,
255
109
  ~toBlock,
256
- ~logSelections,
257
- ~fieldSelection=selectionConfig.fieldSelection,
110
+ ~maxNumLogs=itemsTarget,
111
+ ~registrationIndexes=selection.onEventRegistrations->Array.map(reg => reg.index),
112
+ ~addressesByContractName,
258
113
  ) catch {
259
114
  | HyperSync.GetLogs.Error(error) =>
260
115
  throw(
@@ -301,7 +156,8 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
301
156
  )
302
157
  }
303
158
 
304
- let pageFetchTime = startFetchingBatchTimeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
159
+ let pageFetchTime = startFetchingBatchTimeRef->Performance.secondsSince
160
+ let requestStats = [{Source.method: "getLogs", seconds: pageFetchTime}]
305
161
 
306
162
  //set height and next from block
307
163
  let knownHeight = pageUnsafe.archiveHeight
@@ -311,82 +167,37 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
311
167
  //In the query
312
168
  let heighestBlockQueried = pageUnsafe.nextBlock - 1
313
169
 
314
- let parsingTimeRef = Hrtime.makeTimer()
170
+ let parsingTimeRef = Performance.now()
315
171
 
316
172
  //Parse page items into queue items
317
173
  let parsedQueueItems = []
318
174
 
319
- let handleDecodeFailure = (
320
- ~eventConfig: Internal.evmEventConfig,
321
- ~logIndex,
322
- ~blockNumber,
323
- ~chainId,
324
- ~exn,
325
- ) => {
326
- if !eventConfig.isWildcard {
327
- //Wildcard events can be parsed as undefined if the number of topics
328
- //don't match the event with the given topic0
329
- //Non wildcard events should be expected to be parsed
330
- let msg = `Event ${eventConfig.name} was unexpectedly parsed as undefined`
331
- let logger = Logging.createChildFrom(
332
- ~logger,
333
- ~params={
334
- "chainId": chainId,
335
- "blockNumber": blockNumber,
336
- "logIndex": logIndex,
337
- "decoder": "hypersync-client",
338
- },
339
- )
340
- exn->ErrorHandling.mkLogAndRaise(~msg, ~logger)
341
- }
342
- }
175
+ // Block headers are returned once per number; items reference them by blockNumber.
176
+ let blocksByNumber = Utils.Map.make()
177
+ pageUnsafe.blocks->Array.forEach(block => {
178
+ blocksByNumber->Utils.Map.set(block.number, block)->ignore
179
+ })
180
+ let getBlock = blockNumber => blocksByNumber->Utils.Map.unsafeGet(blockNumber)
343
181
 
344
182
  pageUnsafe.items->Array.forEach(item => {
345
- let chainId = chain->ChainMap.Chain.toChainId
346
- let maybeEventConfig =
347
- eventRouter->EventRouter.get(
348
- ~tag=EventRouter.getEvmEventId(
349
- ~sighash=item.topic0->EvmTypes.Hex.toString,
350
- ~topicCount=item.topicCount,
351
- ),
352
- ~indexingAddresses,
353
- ~contractAddress=item.srcAddress,
354
- ~blockNumber=item.block.number->Option.getUnsafe,
355
- )
356
-
357
- switch maybeEventConfig {
358
- | None => () //ignore events that aren't registered
359
- | Some(eventConfig) =>
360
- switch item.params
361
- ->Nullable.toOption
362
- ->Option.flatMap(Dict.get(_, eventConfig.contractName)) {
363
- | Some(params) =>
364
- parsedQueueItems->Array.push(makeEventBatchQueueItem(item, ~params, ~eventConfig))->ignore
365
- | None =>
366
- handleDecodeFailure(
367
- ~eventConfig,
368
- ~logIndex=item.logIndex,
369
- ~blockNumber=item.block.number->Option.getUnsafe,
370
- ~chainId,
371
- ~exn=UndefinedValue,
372
- )
373
- }
374
- }
183
+ let onEventRegistration =
184
+ onEventRegistrations->Array.getUnsafe(item.onEventRegistrationIndex)
185
+ parsedQueueItems
186
+ ->Array.push(makeEventBatchQueueItem(item, ~onEventRegistration))
187
+ ->ignore
375
188
  })
376
189
 
377
- let parsingTimeElapsed = parsingTimeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
190
+ let parsingTimeElapsed = parsingTimeRef->Performance.secondsSince
378
191
 
379
192
  // Collect (blockNumber, blockHash) pairs we already have from the response —
380
- // one per item's block plus, when present, the rollbackGuard's head block
193
+ // one per returned block plus, when present, the rollbackGuard's head block
381
194
  // and the parent of the range's first block. Duplicates are allowed; reorg
382
195
  // detection notices same-block-number-different-hash collisions itself.
383
196
  let blockHashes = []
384
- pageUnsafe.items->Array.forEach(({block}) => {
385
- switch (block.number, block.hash) {
386
- | (Some(blockNumber), Some(blockHash)) =>
387
- blockHashes->Array.push({ReorgDetection.blockNumber, blockHash})->ignore
388
- | _ => ()
389
- }
197
+ pageUnsafe.blocks->Array.forEach(block => {
198
+ blockHashes
199
+ ->Array.push({ReorgDetection.blockNumber: block.number, blockHash: block.hash})
200
+ ->ignore
390
201
  })
391
202
  switch pageUnsafe.rollbackGuard {
392
203
  | None => ()
@@ -409,13 +220,13 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
409
220
  | Some({timestamp}) => timestamp
410
221
  | None =>
411
222
  switch pageUnsafe.items->Array.get(pageUnsafe.items->Array.length - 1) {
412
- | Some({block}) if block.number->Option.getUnsafe == heighestBlockQueried =>
413
- block.timestamp->Option.getUnsafe
223
+ | Some(item) if item.blockNumber == heighestBlockQueried =>
224
+ getBlock(item.blockNumber).timestamp
414
225
  | _ => 0
415
226
  }
416
227
  }
417
228
 
418
- let totalTimeElapsed = totalTimeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
229
+ let totalTimeElapsed = totalTimeRef->Performance.secondsSince
419
230
 
420
231
  let stats = {
421
232
  totalTimeElapsed,
@@ -426,11 +237,14 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
426
237
  {
427
238
  latestFetchedBlockTimestamp,
428
239
  parsedQueueItems,
240
+ transactionStore: Some(pageUnsafe.transactionStore),
241
+ blockStore: Some(pageUnsafe.blockStore),
429
242
  latestFetchedBlockNumber: heighestBlockQueried,
430
243
  stats,
431
244
  knownHeight,
432
245
  blockHashes,
433
246
  fromBlockQueried: fromBlock,
247
+ requestStats,
434
248
  }
435
249
  }
436
250
 
@@ -441,7 +255,10 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
441
255
  ~sourceName=name,
442
256
  ~chainId=chain->ChainMap.Chain.toChainId,
443
257
  ~logger,
444
- )->Promise.thenResolve(HyperSync.mapExn)
258
+ )->Promise.thenResolve(((queryRes, requestStats)) => {
259
+ Source.result: queryRes->HyperSync.mapExn,
260
+ requestStats,
261
+ })
445
262
 
446
263
  {
447
264
  name,
@@ -451,8 +268,8 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
451
268
  poweredByHyperSync: true,
452
269
  getBlockHashes,
453
270
  getHeightOrThrow: async () => {
454
- let timerRef = Hrtime.makeTimer()
455
- let result = try {
271
+ let timerRef = Performance.now()
272
+ let height = try {
456
273
  await client.getHeight()
457
274
  } catch {
458
275
  | JsExn(e) =>
@@ -465,19 +282,8 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
465
282
  | _ => throw(JsExn(e))
466
283
  }
467
284
  }
468
- let seconds = timerRef->Hrtime.timeSince->Hrtime.toSecondsFloat
469
- Prometheus.SourceRequestCount.increment(
470
- ~sourceName=name,
471
- ~chainId=chain->ChainMap.Chain.toChainId,
472
- ~method="getHeight",
473
- )
474
- Prometheus.SourceRequestCount.addSeconds(
475
- ~sourceName=name,
476
- ~chainId=chain->ChainMap.Chain.toChainId,
477
- ~method="getHeight",
478
- ~seconds,
479
- )
480
- result
285
+ let seconds = timerRef->Performance.secondsSince
286
+ {height, requestStats: [{method: "getHeight", seconds}]}
481
287
  },
482
288
  getItemsOrThrow,
483
289
  createHeightSubscription: (~onHeight) =>