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
@@ -4,19 +4,16 @@ import * as Rpc from "./Rpc.res.mjs";
4
4
  import * as Rest from "../vendored/Rest.res.mjs";
5
5
  import * as Time from "../Time.res.mjs";
6
6
  import * as Utils from "../Utils.res.mjs";
7
- import * as Hrtime from "../bindings/Hrtime.res.mjs";
8
7
  import * as Source from "./Source.res.mjs";
9
8
  import * as Address from "../Address.res.mjs";
10
9
  import * as Logging from "../Logging.res.mjs";
11
10
  import * as Internal from "../Internal.res.mjs";
12
- import * as FetchState from "../FetchState.res.mjs";
13
11
  import * as LazyLoader from "../LazyLoader.res.mjs";
14
- import * as Prometheus from "../Prometheus.res.mjs";
15
- import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
16
- import * as EventRouter from "./EventRouter.res.mjs";
12
+ import * as Performance from "../bindings/Performance.res.mjs";
13
+ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
17
14
  import * as EvmRpcClient from "./EvmRpcClient.res.mjs";
18
- import * as LogSelection from "../LogSelection.res.mjs";
19
15
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
16
+ import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
20
17
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
21
18
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
22
19
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
@@ -27,8 +24,6 @@ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
27
24
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
28
25
  import * as RpcWebSocketHeightStream from "./RpcWebSocketHeightStream.res.mjs";
29
26
 
30
- let QueryTimout = /* @__PURE__ */Primitive_exceptions.create("RpcSource.QueryTimout");
31
-
32
27
  let TransactionDataNotFound = /* @__PURE__ */Primitive_exceptions.create("RpcSource.TransactionDataNotFound");
33
28
 
34
29
  async function getKnownRawBlock(client, blockNumber) {
@@ -49,11 +44,11 @@ function parseBlockInfo(json) {
49
44
  };
50
45
  }
51
46
 
52
- async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumber, backoffMsOnFailure) {
47
+ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumber, backoffMsOnFailure, recordRequest) {
53
48
  let currentBackoff = backoffMsOnFailure;
54
49
  let result;
55
50
  while (Stdlib_Option.isNone(result)) {
56
- Prometheus.SourceRequestCount.increment(sourceName, chain, "eth_getBlockByNumber");
51
+ let timerRef = Performance.now();
57
52
  let exit = 0;
58
53
  let json;
59
54
  try {
@@ -61,6 +56,7 @@ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumbe
61
56
  exit = 1;
62
57
  } catch (raw_err) {
63
58
  let err = Primitive_exceptions.internalToException(raw_err);
59
+ recordRequest("eth_getBlockByNumber", Performance.secondsSince(timerRef));
64
60
  Logging.warn({
65
61
  err: Utils.prettifyExn(err),
66
62
  msg: `Issue while running fetching batch of events from the RPC. Will wait ` + currentBackoff.toString() + `ms and try again.`,
@@ -72,318 +68,128 @@ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumbe
72
68
  currentBackoff = (currentBackoff << 1);
73
69
  }
74
70
  if (exit === 1) {
71
+ recordRequest("eth_getBlockByNumber", Performance.secondsSince(timerRef));
75
72
  result = json;
76
73
  }
77
74
  };
78
75
  return Stdlib_Option.getOrThrow(result, undefined);
79
76
  }
80
77
 
81
- let suggestedRangeRegExp = /retry with the range (\d+)-(\d+)/;
82
-
83
- let blockRangeLimitRegExp = /limited to a (\d+) blocks range/;
84
-
85
- let alchemyRangeRegExp = /up to a (\d+) block range/;
86
-
87
- let cloudflareRangeRegExp = /Max range: (\d+)/;
88
-
89
- let thirdwebRangeRegExp = /Maximum allowed number of requested blocks is (\d+)/;
90
-
91
- let blockpiRangeRegExp = /limited to (\d+) block/;
92
-
93
- let baseRangeRegExp = /block range too large/;
94
-
95
- let maxAllowedBlocksRegExp = /maximum allowed is (\d+) blocks/;
96
-
97
- let blastPaidRegExp = /exceeds the range allowed for your plan \(\d+ > (\d+)\)/;
98
-
99
- let chainstackRegExp = /Block range limit exceeded./;
100
-
101
- let coinbaseRegExp = /please limit the query to at most (\d+) blocks/;
102
-
103
- let publicNodeRegExp = /maximum block range: (\d+)/;
104
-
105
- let hyperliquidRegExp = /query exceeds max block range (\d+)/;
106
-
107
- function parseMessageForBlockRange(message) {
108
- let extractBlockRange = (execResult, isMaxRange) => {
109
- let match = execResult.slice(1);
110
- if (match.length !== 1) {
111
- return;
112
- }
113
- let blockRangeLimit = match[0];
114
- if (blockRangeLimit === undefined) {
115
- return;
116
- }
117
- let blockRangeLimit$1 = Stdlib_Int.fromString(blockRangeLimit, undefined);
118
- if (blockRangeLimit$1 !== undefined && blockRangeLimit$1 > 0) {
119
- return [
120
- blockRangeLimit$1,
121
- isMaxRange
122
- ];
123
- }
124
- };
125
- let execResult = suggestedRangeRegExp.exec(message);
126
- if (execResult == null) {
127
- let execResult$1 = blockRangeLimitRegExp.exec(message);
128
- if (!(execResult$1 == null)) {
129
- return extractBlockRange(execResult$1, true);
130
- }
131
- let execResult$2 = alchemyRangeRegExp.exec(message);
132
- if (!(execResult$2 == null)) {
133
- return extractBlockRange(execResult$2, true);
134
- }
135
- let execResult$3 = cloudflareRangeRegExp.exec(message);
136
- if (!(execResult$3 == null)) {
137
- return extractBlockRange(execResult$3, true);
138
- }
139
- let execResult$4 = thirdwebRangeRegExp.exec(message);
140
- if (!(execResult$4 == null)) {
141
- return extractBlockRange(execResult$4, true);
142
- }
143
- let execResult$5 = blockpiRangeRegExp.exec(message);
144
- if (!(execResult$5 == null)) {
145
- return extractBlockRange(execResult$5, true);
146
- }
147
- let execResult$6 = maxAllowedBlocksRegExp.exec(message);
148
- if (!(execResult$6 == null)) {
149
- return extractBlockRange(execResult$6, true);
150
- }
151
- let match = baseRangeRegExp.exec(message);
152
- if (!(match == null)) {
153
- return [
154
- 2000,
155
- true
156
- ];
157
- }
158
- let execResult$7 = blastPaidRegExp.exec(message);
159
- if (!(execResult$7 == null)) {
160
- return extractBlockRange(execResult$7, true);
161
- }
162
- let match$1 = chainstackRegExp.exec(message);
163
- if (!(match$1 == null)) {
164
- return [
165
- 10000,
166
- true
167
- ];
168
- }
169
- let execResult$8 = coinbaseRegExp.exec(message);
170
- if (!(execResult$8 == null)) {
171
- return extractBlockRange(execResult$8, true);
172
- }
173
- let execResult$9 = publicNodeRegExp.exec(message);
174
- if (!(execResult$9 == null)) {
175
- return extractBlockRange(execResult$9, true);
176
- }
177
- let execResult$10 = hyperliquidRegExp.exec(message);
178
- if (!(execResult$10 == null)) {
179
- return extractBlockRange(execResult$10, true);
180
- } else {
181
- return;
182
- }
78
+ function getErrorMessage(exn) {
79
+ if (exn.RE_EXN_ID === Rpc.JsonRpcError) {
80
+ return exn._1.message;
81
+ }
82
+ if (exn.RE_EXN_ID !== "JsExn") {
83
+ return;
183
84
  }
184
- let match$2 = execResult.slice(1);
185
- if (match$2.length !== 2) {
85
+ let msg = Stdlib_JsExn.message(exn._1);
86
+ if (msg === undefined) {
186
87
  return;
187
88
  }
188
- let fromBlock = match$2[0];
189
- if (fromBlock === undefined) {
89
+ let obj;
90
+ try {
91
+ obj = Stdlib_JSON.Decode.object(JSON.parse(msg));
92
+ } catch (exn$1) {
190
93
  return;
191
94
  }
192
- let toBlock = match$2[1];
193
- if (toBlock === undefined) {
95
+ if (obj === undefined) {
194
96
  return;
195
97
  }
196
- let match$3 = Stdlib_Int.fromString(fromBlock, undefined);
197
- let match$4 = Stdlib_Int.fromString(toBlock, undefined);
198
- if (match$3 !== undefined && match$4 !== undefined && match$4 >= match$3) {
199
- return [
200
- (match$4 - match$3 | 0) + 1 | 0,
201
- false
202
- ];
98
+ let match = obj["errorMessage"];
99
+ if (typeof match === "string") {
100
+ return match;
203
101
  }
204
102
  }
205
103
 
206
- function getSuggestedBlockIntervalFromExn(exn) {
207
- if (exn.RE_EXN_ID === Rpc.JsonRpcError) {
208
- return parseMessageForBlockRange(exn._1.message);
209
- }
104
+ function parseGetNextPageRetryError(exn) {
210
105
  if (exn.RE_EXN_ID !== "JsExn") {
211
106
  return;
212
107
  }
108
+ let msg = Stdlib_JsExn.message(exn._1);
109
+ if (msg === undefined) {
110
+ return;
111
+ }
112
+ let obj;
213
113
  try {
214
- let message = exn._1.error.message;
215
- S$RescriptSchema.assertOrThrow(message, S$RescriptSchema.string);
216
- return parseMessageForBlockRange(message);
114
+ obj = Stdlib_JSON.Decode.object(JSON.parse(msg));
217
115
  } catch (exn$1) {
218
116
  return;
219
117
  }
220
- }
221
-
222
- let maxSuggestedBlockIntervalKey = "max";
223
-
224
- function getNextPage(fromBlock, toBlock, addresses, topicQuery, loadBlock, sc, client, mutSuggestedBlockIntervals, partitionId, sourceName, chainId) {
225
- let queryTimoutPromise = Time.resolvePromiseAfterDelay(sc.queryTimeoutMillis).then(() => Promise.reject({
226
- RE_EXN_ID: QueryTimout,
227
- _1: `Query took longer than ` + (sc.queryTimeoutMillis / 1000 | 0).toString() + ` seconds`
228
- }));
229
- let latestFetchedBlockPromise = loadBlock(toBlock);
230
- Prometheus.SourceRequestCount.increment(sourceName, chainId, "eth_getLogs");
231
- let logsPromise = Rpc.getLogs(client, {
232
- fromBlock: fromBlock,
233
- toBlock: toBlock,
234
- address: addresses,
235
- topics: topicQuery
236
- }).then(async logs => ({
237
- logs: logs,
238
- latestFetchedBlockInfo: await latestFetchedBlockPromise
239
- }));
240
- return Stdlib_Promise.$$catch(Promise.race([
241
- queryTimoutPromise,
242
- logsPromise
243
- ]), err => {
244
- let match = getSuggestedBlockIntervalFromExn(err);
245
- if (match !== undefined) {
246
- let nextBlockIntervalTry = match[0];
247
- mutSuggestedBlockIntervals[match[1] ? maxSuggestedBlockIntervalKey : partitionId] = nextBlockIntervalTry;
248
- throw {
249
- RE_EXN_ID: Source.GetItemsError,
250
- _1: {
251
- TAG: "FailedGettingItems",
252
- exn: err,
253
- attemptedToBlock: toBlock,
254
- retry: {
255
- TAG: "WithSuggestedToBlock",
256
- toBlock: (fromBlock + nextBlockIntervalTry | 0) - 1 | 0
118
+ if (obj === undefined) {
119
+ return;
120
+ }
121
+ let match = obj["kind"];
122
+ let match$1 = obj["attemptedToBlock"];
123
+ let match$2 = obj["retry"];
124
+ if (match === undefined) {
125
+ return;
126
+ }
127
+ if (typeof match !== "string") {
128
+ return;
129
+ }
130
+ if (match !== "Retry") {
131
+ return;
132
+ }
133
+ if (match$1 === undefined) {
134
+ return;
135
+ }
136
+ if (typeof match$1 !== "number") {
137
+ return;
138
+ }
139
+ if (match$2 === undefined) {
140
+ return;
141
+ }
142
+ if (typeof match$2 !== "object" || match$2 === null || Array.isArray(match$2)) {
143
+ return;
144
+ }
145
+ let match$3 = obj["requestStats"];
146
+ let requestStats = match$3 !== undefined ? (
147
+ Array.isArray(match$3) ? Stdlib_Array.filterMap(match$3, s => {
148
+ let o = Stdlib_JSON.Decode.object(s);
149
+ if (o === undefined) {
150
+ return;
257
151
  }
258
- },
259
- Error: new Error()
260
- };
261
- }
262
- let executedBlockInterval = (toBlock - fromBlock | 0) + 1 | 0;
263
- let nextBlockIntervalTry$1 = executedBlockInterval * sc.backoffMultiplicative | 0;
264
- mutSuggestedBlockIntervals[partitionId] = nextBlockIntervalTry$1;
265
- throw {
266
- RE_EXN_ID: Source.GetItemsError,
267
- _1: {
268
- TAG: "FailedGettingItems",
269
- exn: err,
270
- attemptedToBlock: toBlock,
271
- retry: {
272
- TAG: "WithBackoff",
273
- message: `Failed getting data for the block range. Will try smaller block range for the next attempt.`,
274
- backoffMillis: sc.backoffMillis
275
- }
276
- },
277
- Error: new Error()
278
- };
279
- });
280
- }
281
-
282
- function getSelectionConfig(selection, chain) {
283
- let staticTopicSelections = [];
284
- let dynamicEventFilters = [];
285
- selection.eventConfigs.forEach(param => {
286
- let s = param.getEventFiltersOrThrow(chain);
287
- if (s.TAG === "Static") {
288
- staticTopicSelections.push(...s._0);
289
- return;
290
- }
291
- dynamicEventFilters.push(s._0);
292
- });
293
- let match = LogSelection.compressTopicSelections(staticTopicSelections);
294
- let len = match.length;
295
- let getLogSelectionOrThrow;
296
- if (len !== 1) {
297
- if (len !== 0) {
298
- throw {
299
- RE_EXN_ID: Source.GetItemsError,
300
- _1: {
301
- TAG: "UnsupportedSelection",
302
- message: "RPC data-source currently supports event filters only when there's a single wildcard event. Please, create a GitHub issue if it's a blocker for you."
303
- },
304
- Error: new Error()
305
- };
306
- }
307
- let len$1 = dynamicEventFilters.length;
308
- if (len$1 !== 1) {
309
- if (len$1 !== 0) {
310
- throw {
311
- RE_EXN_ID: Source.GetItemsError,
312
- _1: {
313
- TAG: "UnsupportedSelection",
314
- message: "RPC data-source currently supports event filters only when there's a single wildcard event. Please, create a GitHub issue if it's a blocker for you."
315
- },
316
- Error: new Error()
317
- };
318
- }
319
- throw {
320
- RE_EXN_ID: Source.GetItemsError,
321
- _1: {
322
- TAG: "UnsupportedSelection",
323
- message: "Invalid events configuration for the partition. Nothing to fetch. Please, report to the Envio team."
324
- },
325
- Error: new Error()
326
- };
327
- }
328
- let dynamicEventFilter = dynamicEventFilters[0];
329
- if (selection.eventConfigs.length === 1) {
330
- let eventConfig = Utils.$$Array.firstUnsafe(selection.eventConfigs);
331
- getLogSelectionOrThrow = addressesByContractName => {
332
- let addresses = FetchState.addressesByContractNameGetAll(addressesByContractName);
333
- let match = dynamicEventFilter(addresses);
334
- if (match.length !== 1) {
335
- throw {
336
- RE_EXN_ID: Source.GetItemsError,
337
- _1: {
338
- TAG: "UnsupportedSelection",
339
- message: "RPC data-source currently doesn't support an array of event filters. Please, create a GitHub issue if it's a blocker for you."
340
- },
341
- Error: new Error()
342
- };
343
- }
344
- return {
345
- addresses: eventConfig.isWildcard ? undefined : addresses,
346
- topicQuery: Rpc.GetLogs.mapTopicQuery(match[0])
347
- };
348
- };
349
- } else {
350
- throw {
351
- RE_EXN_ID: Source.GetItemsError,
352
- _1: {
353
- TAG: "UnsupportedSelection",
354
- message: "RPC data-source currently supports event filters only when there's a single wildcard event. Please, create a GitHub issue if it's a blocker for you."
355
- },
356
- Error: new Error()
357
- };
152
+ let match = o["method"];
153
+ let match$1 = o["seconds"];
154
+ if (typeof match === "string" && typeof match$1 === "number") {
155
+ return {
156
+ method: match,
157
+ seconds: match$1
158
+ };
159
+ }
160
+ }) : []
161
+ ) : [];
162
+ let match$4 = match$2["tag"];
163
+ let retry;
164
+ if (typeof match$4 === "string") {
165
+ switch (match$4) {
166
+ case "WithBackoff" :
167
+ let match$5 = match$2["message"];
168
+ let match$6 = match$2["backoffMillis"];
169
+ retry = typeof match$5 === "string" && typeof match$6 === "number" ? ({
170
+ TAG: "WithBackoff",
171
+ message: match$5,
172
+ backoffMillis: match$6 | 0
173
+ }) : undefined;
174
+ break;
175
+ case "WithSuggestedToBlock" :
176
+ let match$7 = match$2["toBlock"];
177
+ retry = typeof match$7 === "number" ? ({
178
+ TAG: "WithSuggestedToBlock",
179
+ toBlock: match$7 | 0
180
+ }) : undefined;
181
+ break;
182
+ default:
183
+ retry = undefined;
358
184
  }
359
185
  } else {
360
- let topicSelection = match[0];
361
- if (dynamicEventFilters.length !== 0) {
362
- throw {
363
- RE_EXN_ID: Source.GetItemsError,
364
- _1: {
365
- TAG: "UnsupportedSelection",
366
- message: "RPC data-source currently supports event filters only when there's a single wildcard event. Please, create a GitHub issue if it's a blocker for you."
367
- },
368
- Error: new Error()
369
- };
370
- }
371
- let topicQuery = Rpc.GetLogs.mapTopicQuery(topicSelection);
372
- getLogSelectionOrThrow = addressesByContractName => {
373
- let addresses = FetchState.addressesByContractNameGetAll(addressesByContractName);
374
- return {
375
- addresses: addresses.length !== 0 ? addresses : undefined,
376
- topicQuery: topicQuery
377
- };
378
- };
186
+ retry = undefined;
379
187
  }
380
- return {
381
- getLogSelectionOrThrow: getLogSelectionOrThrow
382
- };
383
- }
384
-
385
- function memoGetSelectionConfig(chain) {
386
- return Utils.$$WeakMap.memoize(selection => getSelectionConfig(selection, chain));
188
+ return Stdlib_Option.map(retry, retry => [
189
+ match$1 | 0,
190
+ retry,
191
+ requestStats
192
+ ]);
387
193
  }
388
194
 
389
195
  let lowercaseAddressSchema = S$RescriptSchema.transform(S$RescriptSchema.string, param => ({
@@ -918,22 +724,35 @@ function makeThrowingGetEventTransaction(getTransactionJson, getReceiptJson, low
918
724
  }
919
725
 
920
726
  function make(param) {
727
+ let headers = param.headers;
921
728
  let lowercaseAddresses = param.lowercaseAddresses;
922
- let allEventParams = param.allEventParams;
923
- let eventRouter = param.eventRouter;
729
+ let onEventRegistrations = param.onEventRegistrations;
924
730
  let chain = param.chain;
925
731
  let url = param.url;
926
732
  let syncConfig = param.syncConfig;
927
733
  let host = Utils.Url.getHostFromUrl(url);
928
734
  let urlHost = host !== undefined ? host : Stdlib_JsError.throwWithMessage(`The RPC url for chain ` + chain.toString() + ` is in incorrect format. The RPC url needs to start with either http:// or https://`);
929
735
  let name = `RPC (` + urlHost + `)`;
930
- let getSelectionConfig = memoGetSelectionConfig(chain);
931
- let mutSuggestedBlockIntervals = {};
932
- let client = Rpc.makeClient(url);
933
- let rpcClient = EvmRpcClient.make(url, undefined);
736
+ let client = Rpc.makeClient(url, headers);
737
+ let rpcClient = EvmRpcClient.make(url, !lowercaseAddresses, syncConfig, undefined, headers, HyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations));
738
+ let pendingRequestStats = [];
739
+ let recordRequest = (method, seconds) => {
740
+ pendingRequestStats.push({
741
+ method: method,
742
+ seconds: seconds
743
+ });
744
+ };
745
+ let drainRequestStats = () => {
746
+ let stats = pendingRequestStats.slice();
747
+ Utils.$$Array.clearInPlace(pendingRequestStats);
748
+ return stats;
749
+ };
934
750
  let makeTransactionLoader = () => LazyLoader.make(transactionHash => {
935
- Prometheus.SourceRequestCount.increment(name, chain, "eth_getTransactionByHash");
936
- return Rest.fetch(Rpc.GetTransactionByHash.rawRoute, transactionHash, client);
751
+ let timerRef = Performance.now();
752
+ return Rest.fetch(Rpc.GetTransactionByHash.rawRoute, transactionHash, client).then(res => {
753
+ recordRequest("eth_getTransactionByHash", Performance.secondsSince(timerRef));
754
+ return res;
755
+ });
937
756
  }, (am, exn) => Logging.error({
938
757
  err: Utils.prettifyExn(exn),
939
758
  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`,
@@ -944,7 +763,7 @@ function make(param) {
944
763
  suggestedFix: "This likely means the RPC url you are using is not responding correctly. Please try another RPC endipoint."
945
764
  }
946
765
  }), undefined, undefined, undefined, undefined);
947
- let makeBlockLoader = () => LazyLoader.make(blockNumber => getKnownRawBlockWithBackoff(client, name, chain, blockNumber, 1000), (am, exn) => Logging.error({
766
+ let makeBlockLoader = () => LazyLoader.make(blockNumber => getKnownRawBlockWithBackoff(client, name, chain, blockNumber, 1000, recordRequest), (am, exn) => Logging.error({
948
767
  err: Utils.prettifyExn(exn),
949
768
  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`,
950
769
  source: name,
@@ -955,8 +774,11 @@ function make(param) {
955
774
  }
956
775
  }), undefined, undefined, undefined, undefined);
957
776
  let makeReceiptLoader = () => LazyLoader.make(transactionHash => {
958
- Prometheus.SourceRequestCount.increment(name, chain, "eth_getTransactionReceipt");
959
- return Rest.fetch(Rpc.GetTransactionReceipt.rawRoute, transactionHash, client);
777
+ let timerRef = Performance.now();
778
+ return Rest.fetch(Rpc.GetTransactionReceipt.rawRoute, transactionHash, client).then(res => {
779
+ recordRequest("eth_getTransactionReceipt", Performance.secondsSince(timerRef));
780
+ return res;
781
+ });
960
782
  }, (am, exn) => Logging.error({
961
783
  err: Utils.prettifyExn(exn),
962
784
  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`,
@@ -998,65 +820,45 @@ function make(param) {
998
820
  Error: new Error()
999
821
  };
1000
822
  }, lowercaseAddresses);
1001
- let convertLogToHyperSyncEvent = log => {
1002
- let hyperSyncLog_removed = log.removed;
1003
- let hyperSyncLog_logIndex = log.logIndex;
1004
- let hyperSyncLog_transactionIndex = log.transactionIndex;
1005
- let hyperSyncLog_transactionHash = log.transactionHash;
1006
- let hyperSyncLog_blockHash = log.blockHash;
1007
- let hyperSyncLog_blockNumber = log.blockNumber;
1008
- let hyperSyncLog_address = Primitive_option.some(log.address);
1009
- let hyperSyncLog_data = log.data;
1010
- let hyperSyncLog_topics = log.topics;
1011
- let hyperSyncLog = {
1012
- removed: hyperSyncLog_removed,
1013
- logIndex: hyperSyncLog_logIndex,
1014
- transactionIndex: hyperSyncLog_transactionIndex,
1015
- transactionHash: hyperSyncLog_transactionHash,
1016
- blockHash: hyperSyncLog_blockHash,
1017
- blockNumber: hyperSyncLog_blockNumber,
1018
- address: hyperSyncLog_address,
1019
- data: hyperSyncLog_data,
1020
- topics: hyperSyncLog_topics
1021
- };
1022
- return {
1023
- log: hyperSyncLog
1024
- };
1025
- };
1026
- let hscDecoder = {
1027
- contents: undefined
1028
- };
1029
- let getHscDecoder = () => {
1030
- let decoder = hscDecoder.contents;
1031
- if (decoder !== undefined) {
1032
- return decoder;
1033
- }
1034
- let decoder$1 = HyperSyncClient.Decoder.fromParams(allEventParams, !lowercaseAddresses);
1035
- hscDecoder.contents = decoder$1;
1036
- return decoder$1;
1037
- };
1038
- let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, indexingAddresses, knownHeight, partitionId, selection, retry, param) => {
1039
- let startFetchingBatchTimeRef = Hrtime.makeTimer();
1040
- let maxSuggestedBlockInterval = mutSuggestedBlockIntervals[maxSuggestedBlockIntervalKey];
1041
- let suggestedBlockInterval = maxSuggestedBlockInterval !== undefined ? maxSuggestedBlockInterval : Stdlib_Option.getOr(mutSuggestedBlockIntervals[partitionId], syncConfig.initialBlockInterval);
823
+ let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, param, knownHeight, partitionId, selection, param$1, retry, param$2) => {
824
+ let startFetchingBatchTimeRef = Performance.now();
1042
825
  let toBlock$1 = toBlock !== undefined ? Primitive_int.min(toBlock, knownHeight) : knownHeight;
1043
- let suggestedToBlock = Primitive_int.max(Primitive_int.min((fromBlock + suggestedBlockInterval | 0) - 1 | 0, toBlock$1), fromBlock);
1044
826
  let firstBlockParentPromise = fromBlock > 0 ? LazyLoader.get(blockLoader.contents, fromBlock - 1 | 0).then(json => parseBlockInfo(json)) : Promise.resolve(undefined);
1045
- let match = getSelectionConfig(selection);
1046
- let match$1 = match.getLogSelectionOrThrow(addressesByContractName);
1047
- let match$2 = await getNextPage(fromBlock, suggestedToBlock, match$1.addresses, match$1.topicQuery, blockNumber => LazyLoader.get(blockLoader.contents, blockNumber).then(parseBlockInfo), syncConfig, client, mutSuggestedBlockIntervals, partitionId, name, chain);
1048
- let latestFetchedBlockInfo = match$2.latestFetchedBlockInfo;
1049
- let logs = match$2.logs;
1050
- let executedBlockInterval = (suggestedToBlock - fromBlock | 0) + 1 | 0;
1051
- if (executedBlockInterval >= suggestedBlockInterval && !(maxSuggestedBlockIntervalKey in mutSuggestedBlockIntervals)) {
1052
- mutSuggestedBlockIntervals[partitionId] = Primitive_int.min(executedBlockInterval + syncConfig.accelerationAdditive | 0, syncConfig.intervalCeiling);
827
+ if (Utils.$$Array.isEmpty(selection.onEventRegistrations)) {
828
+ throw {
829
+ RE_EXN_ID: Source.GetItemsError,
830
+ _1: {
831
+ TAG: "UnsupportedSelection",
832
+ message: "Invalid events configuration for the partition. Nothing to fetch. Please, report to the Envio team."
833
+ },
834
+ Error: new Error()
835
+ };
1053
836
  }
1054
- let hyperSyncEvents = logs.map(convertLogToHyperSyncEvent);
1055
- let parsedEvents;
837
+ let match;
1056
838
  try {
1057
- parsedEvents = await getHscDecoder().decodeLogs(hyperSyncEvents);
839
+ match = await rpcClient.getNextPage({
840
+ fromBlock: fromBlock,
841
+ toBlockCeiling: toBlock$1,
842
+ partitionId: partitionId,
843
+ registrationIndexes: selection.onEventRegistrations.map(reg => reg.index),
844
+ addressesByContractName: addressesByContractName
845
+ });
1058
846
  } catch (raw_exn) {
1059
847
  let exn = Primitive_exceptions.internalToException(raw_exn);
848
+ let match$1 = parseGetNextPageRetryError(exn);
849
+ if (match$1 !== undefined) {
850
+ match$1[2].forEach(stat => recordRequest(stat.method, stat.seconds));
851
+ throw {
852
+ RE_EXN_ID: Source.GetItemsError,
853
+ _1: {
854
+ TAG: "FailedGettingItems",
855
+ exn: exn,
856
+ attemptedToBlock: match$1[0],
857
+ retry: match$1[1]
858
+ },
859
+ Error: new Error()
860
+ };
861
+ }
1060
862
  throw {
1061
863
  RE_EXN_ID: Source.GetItemsError,
1062
864
  _1: {
@@ -1064,26 +866,22 @@ function make(param) {
1064
866
  exn: exn,
1065
867
  attemptedToBlock: toBlock$1,
1066
868
  retry: {
1067
- TAG: "ImpossibleForTheQuery",
1068
- message: "Failed to parse events using hypersync client decoder. Please double-check your ABI."
869
+ TAG: "WithBackoff",
870
+ message: "Unexpected issue while fetching events from the RPC client. Attempt a retry.",
871
+ backoffMillis: retry !== 0 ? 1000 * retry | 0 : 500
1069
872
  }
1070
873
  },
1071
874
  Error: new Error()
1072
875
  };
1073
876
  }
1074
- let parsedQueueItems = await Promise.all(Stdlib_Array.filterMap(Stdlib_Array.zip(logs, parsedEvents), param => {
1075
- let log = param[0];
1076
- let topic0 = Stdlib_Option.getOr(log.topics[0], "0x0");
1077
- let routedAddress = lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(log.address) : Address.Evm.fromAddressOrThrow(log.address);
1078
- let eventConfig = EventRouter.get(eventRouter, EventRouter.getEvmEventId(topic0, log.topics.length), routedAddress, log.blockNumber, indexingAddresses);
1079
- if (eventConfig === undefined) {
1080
- return;
1081
- }
1082
- let decoded = Stdlib_Option.flatMap(Primitive_option.fromNullable(param[1]), __x => __x[eventConfig.contractName]);
1083
- if (decoded === undefined) {
1084
- return;
1085
- }
1086
- let decoded$1 = Primitive_option.valFromOption(decoded);
877
+ let items = match.items;
878
+ match.requestStats.forEach(stat => recordRequest(stat.method, stat.seconds));
879
+ let latestFetchedBlockInfo = await LazyLoader.get(blockLoader.contents, match.toBlock).then(parseBlockInfo);
880
+ let parsedQueueItems = await Promise.all(items.map(param => {
881
+ let decoded = param.params;
882
+ let log = param.log;
883
+ let onEventRegistration = onEventRegistrations[param.onEventRegistrationIndex];
884
+ let eventConfig = onEventRegistration.eventConfig;
1087
885
  return (async () => {
1088
886
  let match;
1089
887
  try {
@@ -1125,27 +923,26 @@ function make(param) {
1125
923
  let block = match[0];
1126
924
  return {
1127
925
  kind: 0,
1128
- eventConfig: eventConfig,
1129
- timestamp: block.timestamp,
926
+ onEventRegistration: onEventRegistration,
1130
927
  chain: chain,
1131
928
  blockNumber: block.number,
1132
- blockHash: block.hash,
1133
929
  logIndex: log.logIndex,
930
+ transactionIndex: log.transactionIndex,
1134
931
  payload: {
1135
932
  contractName: eventConfig.contractName,
1136
933
  eventName: eventConfig.name,
1137
- params: decoded$1,
934
+ params: decoded,
1138
935
  chainId: chain,
1139
- srcAddress: routedAddress,
936
+ srcAddress: log.address,
1140
937
  logIndex: log.logIndex,
1141
- transaction: match[1],
1142
- block: block
938
+ transaction: Primitive_option.some(match[1]),
939
+ block: Primitive_option.some(block)
1143
940
  }
1144
941
  };
1145
942
  })();
1146
943
  }));
1147
944
  let optFirstBlockParent = await firstBlockParentPromise;
1148
- let totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(startFetchingBatchTimeRef));
945
+ let totalTimeElapsed = Performance.secondsSince(startFetchingBatchTimeRef);
1149
946
  let blockHashes = [];
1150
947
  let pushBlockInfo = b => {
1151
948
  blockHashes.push({
@@ -1164,7 +961,8 @@ function make(param) {
1164
961
  if (optFirstBlockParent !== undefined) {
1165
962
  pushBlockInfo(optFirstBlockParent);
1166
963
  }
1167
- logs.forEach(log => {
964
+ items.forEach(param => {
965
+ let log = param.log;
1168
966
  blockHashes.push({
1169
967
  blockHash: log.blockHash,
1170
968
  blockNumber: log.blockNumber
@@ -1174,12 +972,15 @@ function make(param) {
1174
972
  knownHeight: knownHeight,
1175
973
  blockHashes: blockHashes,
1176
974
  parsedQueueItems: parsedQueueItems,
975
+ transactionStore: undefined,
976
+ blockStore: undefined,
1177
977
  fromBlockQueried: fromBlock,
1178
978
  latestFetchedBlockNumber: latestFetchedBlockInfo.number,
1179
979
  latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
1180
980
  stats: {
1181
981
  "total time elapsed (s)": totalTimeElapsed
1182
- }
982
+ },
983
+ requestStats: drainRequestStats()
1183
984
  };
1184
985
  };
1185
986
  let onReorg = param => {
@@ -1187,19 +988,28 @@ function make(param) {
1187
988
  transactionLoader.contents = makeTransactionLoader();
1188
989
  receiptLoader.contents = makeReceiptLoader();
1189
990
  };
1190
- let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => ({
1191
- TAG: "Ok",
1192
- _0: rawBlocks.map(json => {
1193
- let b = parseBlockInfo(json);
1194
- return {
1195
- blockHash: b.hash,
1196
- blockNumber: b.number,
1197
- blockTimestamp: b.timestamp
1198
- };
1199
- })
1200
- })), exn => Promise.resolve({
1201
- TAG: "Error",
1202
- _0: exn
991
+ let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => {
992
+ let result = {
993
+ TAG: "Ok",
994
+ _0: rawBlocks.map(json => {
995
+ let b = parseBlockInfo(json);
996
+ return {
997
+ blockHash: b.hash,
998
+ blockNumber: b.number,
999
+ blockTimestamp: b.timestamp
1000
+ };
1001
+ })
1002
+ };
1003
+ return {
1004
+ result: result,
1005
+ requestStats: drainRequestStats()
1006
+ };
1007
+ }), exn => Promise.resolve({
1008
+ result: {
1009
+ TAG: "Error",
1010
+ _0: exn
1011
+ },
1012
+ requestStats: drainRequestStats()
1203
1013
  }));
1204
1014
  let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => (onHeight => RpcWebSocketHeightStream.subscribe(wsUrl, chain, onHeight)));
1205
1015
  return {
@@ -1210,20 +1020,19 @@ function make(param) {
1210
1020
  pollingInterval: syncConfig.pollingInterval,
1211
1021
  getBlockHashes: getBlockHashes,
1212
1022
  getHeightOrThrow: async () => {
1213
- let timerRef = Hrtime.makeTimer();
1023
+ let timerRef = Performance.now();
1214
1024
  let height;
1215
1025
  try {
1216
1026
  height = await rpcClient.getHeight();
1217
1027
  } catch (exn) {
1218
- let seconds = Hrtime.toSecondsFloat(Hrtime.timeSince(timerRef));
1219
- Prometheus.SourceRequestCount.increment(name, chain, "eth_blockNumber");
1220
- Prometheus.SourceRequestCount.addSeconds(name, chain, "eth_blockNumber", seconds);
1028
+ recordRequest("eth_blockNumber", Performance.secondsSince(timerRef));
1221
1029
  throw exn;
1222
1030
  }
1223
- let seconds$1 = Hrtime.toSecondsFloat(Hrtime.timeSince(timerRef));
1224
- Prometheus.SourceRequestCount.increment(name, chain, "eth_blockNumber");
1225
- Prometheus.SourceRequestCount.addSeconds(name, chain, "eth_blockNumber", seconds$1);
1226
- return height;
1031
+ recordRequest("eth_blockNumber", Performance.secondsSince(timerRef));
1032
+ return {
1033
+ height: height,
1034
+ requestStats: drainRequestStats()
1035
+ };
1227
1036
  },
1228
1037
  getItemsOrThrow: getItemsOrThrow,
1229
1038
  createHeightSubscription: createHeightSubscription,
@@ -1232,16 +1041,12 @@ function make(param) {
1232
1041
  }
1233
1042
 
1234
1043
  export {
1235
- QueryTimout,
1236
1044
  TransactionDataNotFound,
1237
1045
  getKnownRawBlock,
1238
1046
  parseBlockInfo,
1239
1047
  getKnownRawBlockWithBackoff,
1240
- getSuggestedBlockIntervalFromExn,
1241
- maxSuggestedBlockIntervalKey,
1242
- getNextPage,
1243
- getSelectionConfig,
1244
- memoGetSelectionConfig,
1048
+ getErrorMessage,
1049
+ parseGetNextPageRetryError,
1245
1050
  lowercaseAddressSchema,
1246
1051
  checksumAddressSchema,
1247
1052
  makeBlockFieldRegistry,