envio 3.3.0-alpha.1 → 3.3.0-alpha.10

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 (136) hide show
  1. package/evm.schema.json +10 -0
  2. package/index.d.ts +45 -25
  3. package/package.json +7 -7
  4. package/src/Address.res +5 -2
  5. package/src/Address.res.mjs +3 -1
  6. package/src/Api.res +1 -1
  7. package/src/Api.res.mjs +1 -1
  8. package/src/Batch.res +0 -6
  9. package/src/Batch.res.mjs +1 -12
  10. package/src/BatchProcessing.res +7 -12
  11. package/src/BatchProcessing.res.mjs +8 -7
  12. package/src/Bin.res +3 -0
  13. package/src/Bin.res.mjs +4 -0
  14. package/src/ChainFetching.res +43 -9
  15. package/src/ChainFetching.res.mjs +34 -15
  16. package/src/ChainMetadata.res +1 -11
  17. package/src/ChainMetadata.res.mjs +1 -10
  18. package/src/ChainState.res +605 -151
  19. package/src/ChainState.res.mjs +427 -104
  20. package/src/ChainState.resi +72 -4
  21. package/src/Config.res +61 -33
  22. package/src/Config.res.mjs +50 -10
  23. package/src/ContractRegisterContext.res +2 -12
  24. package/src/ContractRegisterContext.res.mjs +3 -5
  25. package/src/Core.res +14 -3
  26. package/src/CrossChainState.res +113 -89
  27. package/src/CrossChainState.res.mjs +64 -60
  28. package/src/CrossChainState.resi +1 -1
  29. package/src/Ecosystem.res +5 -6
  30. package/src/Ecosystem.res.mjs +3 -3
  31. package/src/Envio.res +17 -11
  32. package/src/EnvioGlobal.res +53 -0
  33. package/src/EnvioGlobal.res.mjs +31 -0
  34. package/src/EventConfigBuilder.res +177 -88
  35. package/src/EventConfigBuilder.res.mjs +99 -42
  36. package/src/EventProcessing.res +74 -28
  37. package/src/EventProcessing.res.mjs +55 -29
  38. package/src/ExitOnCaughtUp.res +10 -2
  39. package/src/ExitOnCaughtUp.res.mjs +10 -1
  40. package/src/FetchState.res +544 -356
  41. package/src/FetchState.res.mjs +412 -471
  42. package/src/HandlerLoader.res +8 -104
  43. package/src/HandlerLoader.res.mjs +2 -81
  44. package/src/HandlerRegister.res +518 -144
  45. package/src/HandlerRegister.res.mjs +285 -133
  46. package/src/HandlerRegister.resi +24 -8
  47. package/src/IndexerState.res +10 -3
  48. package/src/IndexerState.res.mjs +11 -4
  49. package/src/IndexerState.resi +2 -1
  50. package/src/IndexingAddresses.res +108 -0
  51. package/src/IndexingAddresses.res.mjs +101 -0
  52. package/src/IndexingAddresses.resi +34 -0
  53. package/src/Internal.res +155 -46
  54. package/src/Internal.res.mjs +30 -2
  55. package/src/LoadLayer.res +5 -5
  56. package/src/LoadLayer.res.mjs +6 -6
  57. package/src/LogSelection.res +102 -165
  58. package/src/LogSelection.res.mjs +101 -116
  59. package/src/Main.res +71 -236
  60. package/src/Main.res.mjs +60 -145
  61. package/src/Metrics.res +74 -0
  62. package/src/Metrics.res.mjs +75 -0
  63. package/src/PgStorage.res +4 -4
  64. package/src/PgStorage.res.mjs +5 -5
  65. package/src/Prometheus.res +10 -63
  66. package/src/Prometheus.res.mjs +124 -171
  67. package/src/PruneStaleHistory.res +2 -2
  68. package/src/PruneStaleHistory.res.mjs +3 -3
  69. package/src/RawEvent.res +7 -2
  70. package/src/RawEvent.res.mjs +4 -4
  71. package/src/Rollback.res +3 -3
  72. package/src/Rollback.res.mjs +4 -4
  73. package/src/RollbackCommit.res +4 -1
  74. package/src/RollbackCommit.res.mjs +3 -2
  75. package/src/SimulateDeadInputTracker.res +85 -0
  76. package/src/SimulateDeadInputTracker.res.mjs +73 -0
  77. package/src/SimulateDeadInputTracker.resi +12 -0
  78. package/src/SimulateItems.res +91 -23
  79. package/src/SimulateItems.res.mjs +55 -32
  80. package/src/TestIndexer.res +54 -40
  81. package/src/TestIndexer.res.mjs +37 -30
  82. package/src/bindings/Performance.res +7 -0
  83. package/src/bindings/Performance.res.mjs +21 -0
  84. package/src/bindings/Performance.resi +7 -0
  85. package/src/bindings/Viem.res +0 -41
  86. package/src/bindings/Viem.res.mjs +1 -43
  87. package/src/sources/BlockStore.res +46 -0
  88. package/src/sources/BlockStore.res.mjs +24 -0
  89. package/src/sources/EventRouter.res +36 -33
  90. package/src/sources/EventRouter.res.mjs +13 -14
  91. package/src/sources/Evm.res +83 -72
  92. package/src/sources/Evm.res.mjs +53 -69
  93. package/src/sources/EvmChain.res +18 -20
  94. package/src/sources/EvmChain.res.mjs +15 -15
  95. package/src/sources/EvmRpcClient.res +74 -5
  96. package/src/sources/EvmRpcClient.res.mjs +13 -4
  97. package/src/sources/FieldMask.res +39 -0
  98. package/src/sources/FieldMask.res.mjs +42 -0
  99. package/src/sources/Fuel.res +9 -6
  100. package/src/sources/Fuel.res.mjs +5 -10
  101. package/src/sources/HyperFuelSource.res +46 -50
  102. package/src/sources/HyperFuelSource.res.mjs +64 -54
  103. package/src/sources/HyperSync.res +39 -7
  104. package/src/sources/HyperSync.res.mjs +57 -37
  105. package/src/sources/HyperSync.resi +12 -2
  106. package/src/sources/HyperSyncClient.res +22 -111
  107. package/src/sources/HyperSyncClient.res.mjs +2 -30
  108. package/src/sources/HyperSyncHeightStream.res +1 -8
  109. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  110. package/src/sources/HyperSyncSource.res +94 -107
  111. package/src/sources/HyperSyncSource.res.mjs +82 -86
  112. package/src/sources/Rpc.res +15 -47
  113. package/src/sources/Rpc.res.mjs +25 -56
  114. package/src/sources/RpcSource.res +320 -467
  115. package/src/sources/RpcSource.res.mjs +268 -385
  116. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  117. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  118. package/src/sources/SimulateSource.res +10 -4
  119. package/src/sources/SimulateSource.res.mjs +16 -6
  120. package/src/sources/Source.res +34 -6
  121. package/src/sources/SourceManager.res +77 -19
  122. package/src/sources/SourceManager.res.mjs +63 -21
  123. package/src/sources/SourceManager.resi +10 -0
  124. package/src/sources/Svm.res +31 -16
  125. package/src/sources/Svm.res.mjs +36 -13
  126. package/src/sources/SvmHyperSyncClient.res +5 -32
  127. package/src/sources/SvmHyperSyncSource.res +159 -134
  128. package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
  129. package/src/sources/TransactionStore.res +49 -0
  130. package/src/sources/TransactionStore.res.mjs +30 -0
  131. package/src/tui/Tui.res +13 -16
  132. package/src/tui/Tui.res.mjs +12 -14
  133. package/svm.schema.json +49 -37
  134. package/src/bindings/Hrtime.res +0 -58
  135. package/src/bindings/Hrtime.res.mjs +0 -90
  136. package/src/bindings/Hrtime.resi +0 -30
@@ -16,9 +16,15 @@ let reraisIfRateLimited = exn =>
16
16
 
17
17
  type logsQueryPage = {
18
18
  items: array<HyperSyncClient.EventItems.item>,
19
+ // Block headers referenced by `items`, deduplicated by block number.
20
+ blocks: array<HyperSyncClient.EventItems.blockHeader>,
19
21
  nextBlock: int,
20
22
  archiveHeight: int,
21
23
  rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
24
+ // Page store owning this page's raw transactions.
25
+ transactionStore: TransactionStore.t,
26
+ // Page store owning this page's raw blocks.
27
+ blockStore: BlockStore.t,
22
28
  }
23
29
 
24
30
  type missingParams = {
@@ -60,6 +66,7 @@ module GetLogs = {
60
66
  ~toBlockInclusive,
61
67
  ~addressesWithTopics,
62
68
  ~fieldSelection,
69
+ ~maxNumLogs,
63
70
  ): HyperSyncClient.QueryTypes.query => {
64
71
  fromBlock,
65
72
  toBlockExclusive: ?switch toBlockInclusive {
@@ -68,6 +75,7 @@ module GetLogs = {
68
75
  },
69
76
  logs: addressesWithTopics,
70
77
  fieldSelection,
78
+ maxNumLogs,
71
79
  }
72
80
 
73
81
  // Rust encodes structured failures as a JSON payload in the napi error's
@@ -101,6 +109,7 @@ module GetLogs = {
101
109
  ~toBlock,
102
110
  ~logSelections: array<LogSelection.t>,
103
111
  ~fieldSelection,
112
+ ~maxNumLogs,
104
113
  ): logsQueryPage => {
105
114
  let addressesWithTopics = logSelections->Array.flatMap(({addresses, topicSelections}) =>
106
115
  topicSelections->Array.map(({topic0, topic1, topic2, topic3}) => {
@@ -119,9 +128,10 @@ module GetLogs = {
119
128
  ~toBlockInclusive=toBlock,
120
129
  ~addressesWithTopics,
121
130
  ~fieldSelection,
131
+ ~maxNumLogs,
122
132
  )
123
133
 
124
- let res = switch await client.getEventItems(~query) {
134
+ let (res, transactionStore, blockStore) = switch await client.getEventItems(~query) {
125
135
  | res => res
126
136
  | exception exn =>
127
137
  reraisIfRateLimited(exn)
@@ -137,9 +147,12 @@ module GetLogs = {
137
147
 
138
148
  {
139
149
  items: res.items,
150
+ blocks: res.blocks,
140
151
  nextBlock: res.nextBlock,
141
152
  archiveHeight: res.archiveHeight->Option.getOr(0), //Archive Height is only None if height is 0
142
153
  rollbackGuard: res.rollbackGuard,
154
+ transactionStore,
155
+ blockStore,
143
156
  }
144
157
  }
145
158
  }
@@ -196,6 +209,7 @@ module BlockData = {
196
209
  ~sourceName,
197
210
  ~chainId,
198
211
  ~logger,
212
+ ~requestStats: array<Source.requestStat>,
199
213
  ): queryResponse<array<ReorgDetection.blockDataWithTimestamp>> => {
200
214
  let body = makeRequestBody(~fromBlock, ~toBlock)
201
215
 
@@ -208,7 +222,7 @@ module BlockData = {
208
222
  },
209
223
  )
210
224
 
211
- Prometheus.SourceRequestCount.increment(~sourceName, ~chainId, ~method="getBlockHashes")
225
+ let timerRef = Performance.now()
212
226
  let maybeSuccessfulRes = switch await client.get(~query=body) {
213
227
  | exception exn =>
214
228
  reraisIfRateLimited(exn)
@@ -216,6 +230,9 @@ module BlockData = {
216
230
  | res if res.nextBlock <= fromBlock => None
217
231
  | res => Some(res)
218
232
  }
233
+ requestStats
234
+ ->Array.push({Source.method: "getBlockHashes", seconds: timerRef->Performance.secondsSince})
235
+ ->ignore
219
236
 
220
237
  // If the block is not found, retry the query. This can occur since replicas of hypersync might not have caught up yet
221
238
  switch maybeSuccessfulRes {
@@ -225,7 +242,15 @@ module BlockData = {
225
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.`,
226
243
  )
227
244
  await Time.resolvePromiseAfterDelay(~delayMilliseconds)
228
- 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
+ )
229
254
  }
230
255
  | Some(res) =>
231
256
  switch res->convertResponse {
@@ -238,6 +263,7 @@ module BlockData = {
238
263
  ~sourceName,
239
264
  ~chainId,
240
265
  ~logger,
266
+ ~requestStats,
241
267
  )
242
268
  restRes->Result.map(rest => datas->Array.concat(rest))
243
269
  }
@@ -252,8 +278,9 @@ module BlockData = {
252
278
  ~sourceName,
253
279
  ~chainId,
254
280
  ~logger,
255
- ) => {
256
- switch blockNumbers->Array.get(0) {
281
+ ): (queryResponse<array<ReorgDetection.blockDataWithTimestamp>>, array<Source.requestStat>) => {
282
+ let requestStats = []
283
+ let result = switch blockNumbers->Array.get(0) {
257
284
  | None => Ok([])
258
285
  | Some(firstBlock) => {
259
286
  let fromBlock = ref(firstBlock)
@@ -281,6 +308,7 @@ module BlockData = {
281
308
  ~sourceName,
282
309
  ~chainId,
283
310
  ~logger,
311
+ ~requestStats,
284
312
  )
285
313
  let filtered = res->Result.map(datas => {
286
314
  datas->Array.filter(data => set->Utils.Set.delete(data.blockNumber))
@@ -295,10 +323,12 @@ module BlockData = {
295
323
  filtered
296
324
  }
297
325
  }
326
+ (result, requestStats)
298
327
  }
299
328
  }
300
329
 
301
- let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
330
+ let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) => {
331
+ let requestStats = []
302
332
  BlockData.queryBlockData(
303
333
  ~client,
304
334
  ~fromBlock=blockNumber,
@@ -306,5 +336,7 @@ let queryBlockData = (~client, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
306
336
  ~sourceName,
307
337
  ~chainId,
308
338
  ~logger,
309
- )->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
+ }
310
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";
@@ -62,12 +62,13 @@ function mapExn(queryResponse) {
62
62
 
63
63
  let $$Error = /* @__PURE__ */Primitive_exceptions.create("HyperSync.GetLogs.Error");
64
64
 
65
- function makeRequestBody(fromBlock, toBlockInclusive, addressesWithTopics, fieldSelection) {
65
+ function makeRequestBody(fromBlock, toBlockInclusive, addressesWithTopics, fieldSelection, maxNumLogs) {
66
66
  return {
67
67
  fromBlock: fromBlock,
68
68
  toBlock: toBlockInclusive !== undefined ? toBlockInclusive + 1 | 0 : undefined,
69
69
  logs: addressesWithTopics,
70
- fieldSelection: fieldSelection
70
+ fieldSelection: fieldSelection,
71
+ maxNumLogs: maxNumLogs
71
72
  };
72
73
  }
73
74
 
@@ -92,7 +93,7 @@ function extractMissingParams(exn) {
92
93
  }
93
94
  }
94
95
 
95
- async function query(client, fromBlock, toBlock, logSelections, fieldSelection) {
96
+ async function query(client, fromBlock, toBlock, logSelections, fieldSelection, maxNumLogs) {
96
97
  let addressesWithTopics = logSelections.flatMap(param => {
97
98
  let addresses = param.addresses;
98
99
  return param.topicSelections.map(param => {
@@ -100,10 +101,10 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
100
101
  return HyperSyncClient.QueryTypes.makeLogSelection(addresses, topics);
101
102
  });
102
103
  });
103
- let query$1 = makeRequestBody(fromBlock, toBlock, addressesWithTopics, fieldSelection);
104
- let res;
104
+ let query$1 = makeRequestBody(fromBlock, toBlock, addressesWithTopics, fieldSelection, maxNumLogs);
105
+ let match;
105
106
  try {
106
- res = await client.getEventItems(query$1);
107
+ match = await client.getEventItems(query$1);
107
108
  } catch (raw_exn) {
108
109
  let exn = Primitive_exceptions.internalToException(raw_exn);
109
110
  reraisIfRateLimited(exn);
@@ -120,6 +121,7 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
120
121
  }
121
122
  throw exn;
122
123
  }
124
+ let res = match[0];
123
125
  if (res.nextBlock <= fromBlock) {
124
126
  throw {
125
127
  RE_EXN_ID: $$Error,
@@ -129,9 +131,12 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection)
129
131
  }
130
132
  return {
131
133
  items: res.items,
134
+ blocks: res.blocks,
132
135
  nextBlock: res.nextBlock,
133
136
  archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0),
134
- rollbackGuard: res.rollbackGuard
137
+ rollbackGuard: res.rollbackGuard,
138
+ transactionStore: match[1],
139
+ blockStore: match[2]
135
140
  };
136
141
  }
137
142
 
@@ -187,14 +192,14 @@ function convertResponse(res) {
187
192
  }));
188
193
  }
189
194
 
190
- async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger) {
195
+ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger, requestStats) {
191
196
  let body = makeRequestBody$1(fromBlock, toBlock);
192
197
  let logger$1 = Logging.createChildFrom(logger, {
193
198
  logType: "HyperSync get block hash query",
194
199
  fromBlock: fromBlock,
195
200
  toBlock: toBlock
196
201
  });
197
- Prometheus.SourceRequestCount.increment(sourceName, chainId, "getBlockHashes");
202
+ let timerRef = Performance.now();
198
203
  let maybeSuccessfulRes;
199
204
  let exit = 0;
200
205
  let res;
@@ -209,6 +214,10 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
209
214
  if (exit === 1) {
210
215
  maybeSuccessfulRes = res.nextBlock <= fromBlock ? undefined : res;
211
216
  }
217
+ requestStats.push({
218
+ method: "getBlockHashes",
219
+ seconds: Performance.secondsSince(timerRef)
220
+ });
212
221
  if (maybeSuccessfulRes !== undefined) {
213
222
  let err = convertResponse(maybeSuccessfulRes);
214
223
  if (err.TAG !== "Ok") {
@@ -218,48 +227,59 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
218
227
  return err;
219
228
  }
220
229
  let datas = err._0;
221
- 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);
222
231
  return Stdlib_Result.map(restRes, rest => datas.concat(rest));
223
232
  }
224
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.`);
225
234
  await Time.resolvePromiseAfterDelay(100);
226
- return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1);
235
+ return await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger$1, requestStats);
227
236
  }
228
237
 
229
238
  async function queryBlockDataMulti(client, blockNumbers, sourceName, chainId, logger) {
239
+ let requestStats = [];
230
240
  let firstBlock = blockNumbers[0];
231
- if (firstBlock === undefined) {
232
- 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 = {
233
267
  TAG: "Ok",
234
268
  _0: []
235
269
  };
236
270
  }
237
- let fromBlock = firstBlock;
238
- let toBlock = firstBlock;
239
- let set = new Set();
240
- for (let idx = 0, idx_finish = blockNumbers.length; idx < idx_finish; ++idx) {
241
- let blockNumber = blockNumbers[idx];
242
- if (blockNumber < fromBlock) {
243
- fromBlock = blockNumber;
244
- }
245
- if (blockNumber > toBlock) {
246
- toBlock = blockNumber;
247
- }
248
- set.add(blockNumber);
249
- }
250
- if ((toBlock - fromBlock | 0) > 1000) {
251
- Stdlib_JsError.throwWithMessage(`Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: ` + fromBlock.toString() + `-` + toBlock.toString());
252
- }
253
- let res = await queryBlockData(client, fromBlock, toBlock, sourceName, chainId, logger);
254
- let filtered = Stdlib_Result.map(res, datas => datas.filter(data => set.delete(data.blockNumber)));
255
- if (set.size > 0) {
256
- Stdlib_JsError.throwWithMessage(`Invalid response. Failed to get block data for block numbers: ` + Array.from(set).join(", "));
257
- }
258
- return filtered;
271
+ return [
272
+ result,
273
+ requestStats
274
+ ];
259
275
  }
260
276
 
261
277
  function queryBlockData$1(client, blockNumber, sourceName, chainId, logger) {
262
- 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
+ ]);
263
283
  }
264
284
 
265
285
  let GetLogs = {
@@ -1,8 +1,11 @@
1
1
  type logsQueryPage = {
2
2
  items: array<HyperSyncClient.EventItems.item>,
3
+ blocks: array<HyperSyncClient.EventItems.blockHeader>,
3
4
  nextBlock: int,
4
5
  archiveHeight: int,
5
6
  rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
7
+ transactionStore: TransactionStore.t,
8
+ blockStore: BlockStore.t,
6
9
  }
7
10
 
8
11
  type missingParams = {
@@ -31,6 +34,7 @@ module GetLogs: {
31
34
  ~toBlock: option<int>,
32
35
  ~logSelections: array<LogSelection.t>,
33
36
  ~fieldSelection: HyperSyncClient.QueryTypes.fieldSelection,
37
+ ~maxNumLogs: int,
34
38
  ) => promise<logsQueryPage>
35
39
  }
36
40
 
@@ -40,7 +44,10 @@ let queryBlockData: (
40
44
  ~sourceName: string,
41
45
  ~chainId: int,
42
46
  ~logger: Pino.t,
43
- ) => promise<queryResponse<option<ReorgDetection.blockDataWithTimestamp>>>
47
+ ) => promise<(
48
+ queryResponse<option<ReorgDetection.blockDataWithTimestamp>>,
49
+ array<Source.requestStat>,
50
+ )>
44
51
 
45
52
  let queryBlockDataMulti: (
46
53
  ~client: HyperSyncClient.t,
@@ -48,6 +55,9 @@ let queryBlockDataMulti: (
48
55
  ~sourceName: string,
49
56
  ~chainId: int,
50
57
  ~logger: Pino.t,
51
- ) => promise<queryResponse<array<ReorgDetection.blockDataWithTimestamp>>>
58
+ ) => promise<(
59
+ queryResponse<array<ReorgDetection.blockDataWithTimestamp>>,
60
+ array<Source.requestStat>,
61
+ )>
52
62
 
53
63
  let mapExn: queryResponse<'a> => result<'a, exn>
@@ -208,90 +208,6 @@ module ResponseTypes = {
208
208
  mixHash?: string,
209
209
  }
210
210
 
211
- type accessList = {
212
- address?: Address.t,
213
- storageKeys?: array<string>,
214
- }
215
-
216
- let accessListSchema = S.object(s => {
217
- address: ?s.field("address", S.option(Address.schema)),
218
- storageKeys: ?s.field("storageKeys", S.option(S.array(S.string))),
219
- })
220
-
221
- type authorizationList = {
222
- chainId: bigint,
223
- address: Address.t,
224
- nonce: int,
225
- yParity: [#0 | #1],
226
- r: string,
227
- s: string,
228
- }
229
-
230
- let authorizationListSchema = S.object(s => {
231
- chainId: s.field("chainId", S.bigint),
232
- address: s.field("address", Address.schema),
233
- nonce: s.field("nonce", S.int),
234
- yParity: s.field("yParity", S.enum([#0, #1])),
235
- r: s.field("r", S.string),
236
- s: s.field("s", S.string),
237
- })
238
-
239
- type transaction = {
240
- blockHash?: string,
241
- blockNumber?: int,
242
- from?: string,
243
- gas?: bigint,
244
- gasPrice?: bigint,
245
- hash?: string,
246
- input?: string,
247
- nonce?: bigint,
248
- to?: string,
249
- transactionIndex?: int,
250
- value?: bigint,
251
- v?: string,
252
- r?: string,
253
- s?: string,
254
- yParity?: string,
255
- maxPriorityFeePerGas?: bigint,
256
- maxFeePerGas?: bigint,
257
- chainId?: int,
258
- accessList?: array<accessList>,
259
- maxFeePerBlobGas?: bigint,
260
- blobVersionedHashes?: array<string>,
261
- cumulativeGasUsed?: bigint,
262
- effectiveGasPrice?: bigint,
263
- gasUsed?: bigint,
264
- contractAddress?: string,
265
- logsBloom?: string,
266
- @as("type") type_?: int,
267
- root?: string,
268
- status?: int,
269
- l1Fee?: bigint,
270
- l1GasPrice?: bigint,
271
- l1GasUsed?: bigint,
272
- l1FeeScalar?: float,
273
- gasUsedForL1?: bigint,
274
- authorizationList?: array<authorizationList>,
275
- }
276
-
277
- type log = {
278
- removed?: bool,
279
- @as("logIndex") index?: int,
280
- transactionIndex?: int,
281
- transactionHash?: string,
282
- blockHash?: string,
283
- blockNumber?: int,
284
- address?: Address.t,
285
- data?: string,
286
- topics?: array<Nullable.t<EvmTypes.Hex.t>>,
287
- }
288
-
289
- type event = {
290
- transaction?: transaction,
291
- block?: block,
292
- log: log,
293
- }
294
-
295
211
  type rollbackGuard = {
296
212
  blockNumber: int,
297
213
  timestamp: int,
@@ -303,11 +219,7 @@ module ResponseTypes = {
303
219
 
304
220
  type query = QueryTypes.query
305
221
 
306
- type queryResponseData = {
307
- blocks: array<ResponseTypes.block>,
308
- transactions: array<ResponseTypes.transaction>,
309
- logs: array<ResponseTypes.log>,
310
- }
222
+ type queryResponseData = {blocks: array<ResponseTypes.block>}
311
223
 
312
224
  type queryResponse = {
313
225
  archiveHeight: option<int>,
@@ -325,25 +237,6 @@ module Decoder = {
325
237
  contractName: string,
326
238
  params: array<Internal.paramMeta>,
327
239
  }
328
-
329
- // Decoded params keyed by contract name. Contracts that emit the same-signature
330
- // event share one decode but get their own param names, so the caller picks the
331
- // entry for the contract its router resolved the log to.
332
- type tWithParams = {
333
- decodeLogs: array<ResponseTypes.event> => promise<
334
- array<Nullable.t<dict<Internal.eventParams>>>,
335
- >,
336
- }
337
-
338
- @send
339
- external classFromParams: (
340
- Core.evmDecoderCtor,
341
- array<eventParamsInput>,
342
- ~checksumAddresses: bool=?,
343
- ) => tWithParams = "fromParams"
344
-
345
- let fromParams = (eventParams, ~checksumAddresses=?) =>
346
- Core.getAddon().evmDecoder->classFromParams(eventParams, ~checksumAddresses?)
347
240
  }
348
241
 
349
242
  module EventItems = {
@@ -352,14 +245,28 @@ module EventItems = {
352
245
  srcAddress: Address.t,
353
246
  topic0: EvmTypes.Hex.t,
354
247
  topicCount: int,
355
- block: ResponseTypes.block,
356
- transaction: ResponseTypes.transaction,
248
+ // Number of the block this log belongs to; the block itself is resolved from
249
+ // `response.blocks`, deduplicated across items sharing a block.
250
+ blockNumber: int,
251
+ // Key (with the block number) into the transaction store; the transaction
252
+ // is resolved from the store on demand.
253
+ transactionIndex: int,
357
254
  params: Nullable.t<dict<Internal.eventParams>>,
358
255
  }
359
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
+
360
265
  type response = {
361
266
  archiveHeight: option<int>,
362
267
  nextBlock: int,
268
+ // One header per block number referenced by `items`.
269
+ blocks: array<blockHeader>,
363
270
  items: array<item>,
364
271
  rollbackGuard: option<ResponseTypes.rollbackGuard>,
365
272
  }
@@ -367,7 +274,11 @@ module EventItems = {
367
274
 
368
275
  type t = {
369
276
  get: (~query: query) => promise<queryResponse>,
370
- getEventItems: (~query: query) => promise<EventItems.response>,
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)>,
371
282
  getHeight: unit => promise<int>,
372
283
  }
373
284
 
@@ -2,8 +2,6 @@
2
2
 
3
3
  import * as Core from "../Core.res.mjs";
4
4
  import * as Utils from "../Utils.res.mjs";
5
- import * as Address from "../Address.res.mjs";
6
- import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
7
5
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
8
6
 
9
7
  let serializationFormatSchema = S$RescriptSchema.$$enum([
@@ -36,35 +34,9 @@ let QueryTypes = {
36
34
  makeLogSelection: makeLogSelection
37
35
  };
38
36
 
39
- let accessListSchema = S$RescriptSchema.object(s => ({
40
- address: s.f("address", S$RescriptSchema.option(Address.schema)),
41
- storageKeys: s.f("storageKeys", S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string)))
42
- }));
37
+ let ResponseTypes = {};
43
38
 
44
- let authorizationListSchema = S$RescriptSchema.object(s => ({
45
- chainId: s.f("chainId", S$RescriptSchema.bigint),
46
- address: s.f("address", Address.schema),
47
- nonce: s.f("nonce", S$RescriptSchema.int),
48
- yParity: s.f("yParity", S$RescriptSchema.$$enum([
49
- 0,
50
- 1
51
- ])),
52
- r: s.f("r", S$RescriptSchema.string),
53
- s: s.f("s", S$RescriptSchema.string)
54
- }));
55
-
56
- let ResponseTypes = {
57
- accessListSchema: accessListSchema,
58
- authorizationListSchema: authorizationListSchema
59
- };
60
-
61
- function fromParams(eventParams, checksumAddresses) {
62
- return Core.getAddon().EvmDecoder.fromParams(eventParams, checksumAddresses !== undefined ? Primitive_option.valFromOption(checksumAddresses) : undefined);
63
- }
64
-
65
- let Decoder = {
66
- fromParams: fromParams
67
- };
39
+ let Decoder = {};
68
40
 
69
41
  let EventItems = {};
70
42
 
@@ -35,8 +35,7 @@ let subscribe = (~hyperSyncUrl, ~apiToken, ~chainId, ~onHeight: int => unit): (u
35
35
  and scheduleReconnect = () => {
36
36
  // Clear any pending stale/reconnect timeout to avoid double reconnect
37
37
  timeoutIdRef.contents->clearTimeout
38
- let delay =
39
- baseDuration * Math.pow(2.0, ~exp=errorCount.contents->Int.toFloat)->Float.toInt
38
+ let delay = baseDuration * Math.pow(2.0, ~exp=errorCount.contents->Int.toFloat)->Float.toInt
40
39
  timeoutIdRef := setTimeout(() => refreshEventSource(), Pervasives.min(delay, 60_000))
41
40
  }
42
41
  and refreshEventSource = () => {
@@ -102,12 +101,6 @@ let subscribe = (~hyperSyncUrl, ~apiToken, ~chainId, ~onHeight: int => unit): (u
102
101
  es->EventSource.addEventListener("height", event => {
103
102
  switch event.data->Int.fromString {
104
103
  | Some(height) =>
105
- // Track the SSE height event
106
- Prometheus.SourceRequestCount.increment(
107
- ~sourceName="HyperSync",
108
- ~chainId,
109
- ~method="heightStream",
110
- )
111
104
  // On a successful height event, update the timeout
112
105
  updateTimeoutId()
113
106
  // Call the callback with the new height
@@ -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 {