envio 3.0.0-alpha.2 → 3.0.0-alpha.20
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.
- package/README.md +164 -30
- package/bin.mjs +49 -0
- package/evm.schema.json +79 -169
- package/fuel.schema.json +50 -21
- package/index.d.ts +497 -1
- package/index.js +4 -0
- package/package.json +42 -31
- package/rescript.json +4 -1
- package/src/Batch.res +11 -8
- package/src/Batch.res.mjs +11 -9
- package/src/ChainFetcher.res +531 -0
- package/src/ChainFetcher.res.mjs +339 -0
- package/src/ChainManager.res +190 -0
- package/src/ChainManager.res.mjs +166 -0
- package/src/Change.res +3 -3
- package/src/Config.gen.ts +19 -0
- package/src/Config.res +737 -22
- package/src/Config.res.mjs +703 -26
- package/src/{Indexer.res → Ctx.res} +1 -1
- package/src/Ecosystem.res +9 -124
- package/src/Ecosystem.res.mjs +19 -160
- package/src/Env.res +30 -74
- package/src/Env.res.mjs +25 -87
- package/src/Envio.gen.ts +3 -1
- package/src/Envio.res +20 -9
- package/src/EventProcessing.res +469 -0
- package/src/EventProcessing.res.mjs +337 -0
- package/src/EvmTypes.gen.ts +6 -0
- package/src/EvmTypes.res +1 -0
- package/src/FetchState.res +1256 -639
- package/src/FetchState.res.mjs +1135 -612
- package/src/GlobalState.res +1190 -0
- package/src/GlobalState.res.mjs +1183 -0
- package/src/GlobalStateManager.res +68 -0
- package/src/GlobalStateManager.res.mjs +75 -0
- package/src/GlobalStateManager.resi +7 -0
- package/src/HandlerLoader.res +89 -0
- package/src/HandlerLoader.res.mjs +79 -0
- package/src/HandlerRegister.res +357 -0
- package/src/HandlerRegister.res.mjs +299 -0
- package/src/{EventRegister.resi → HandlerRegister.resi} +13 -13
- package/src/Hasura.res +111 -175
- package/src/Hasura.res.mjs +88 -150
- package/src/InMemoryStore.res +1 -1
- package/src/InMemoryStore.res.mjs +3 -3
- package/src/InMemoryTable.res +1 -1
- package/src/InMemoryTable.res.mjs +1 -1
- package/src/Internal.gen.ts +4 -0
- package/src/Internal.res +230 -12
- package/src/Internal.res.mjs +115 -1
- package/src/LoadLayer.res +444 -0
- package/src/LoadLayer.res.mjs +296 -0
- package/src/LoadLayer.resi +32 -0
- package/src/LogSelection.res +33 -27
- package/src/LogSelection.res.mjs +6 -0
- package/src/Logging.res +21 -7
- package/src/Logging.res.mjs +16 -8
- package/src/Main.res +377 -0
- package/src/Main.res.mjs +339 -0
- package/src/Persistence.res +7 -21
- package/src/Persistence.res.mjs +3 -3
- package/src/PgStorage.gen.ts +10 -0
- package/src/PgStorage.res +116 -69
- package/src/PgStorage.res.d.mts +5 -0
- package/src/PgStorage.res.mjs +93 -50
- package/src/Prometheus.res +294 -224
- package/src/Prometheus.res.mjs +353 -340
- package/src/ReorgDetection.res +6 -10
- package/src/ReorgDetection.res.mjs +6 -6
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +2 -2
- package/src/Sink.res +4 -2
- package/src/Sink.res.mjs +2 -1
- package/src/TableIndices.res +0 -1
- package/src/TestIndexer.res +692 -0
- package/src/TestIndexer.res.mjs +527 -0
- package/src/TestIndexerProxyStorage.res +205 -0
- package/src/TestIndexerProxyStorage.res.mjs +151 -0
- package/src/TopicFilter.res +1 -1
- package/src/Types.ts +1 -1
- package/src/UserContext.res +424 -0
- package/src/UserContext.res.mjs +279 -0
- package/src/Utils.res +97 -26
- package/src/Utils.res.mjs +91 -44
- package/src/bindings/BigInt.res +10 -0
- package/src/bindings/BigInt.res.mjs +15 -0
- package/src/bindings/ClickHouse.res +120 -23
- package/src/bindings/ClickHouse.res.mjs +118 -28
- package/src/bindings/DateFns.res +74 -0
- package/src/bindings/DateFns.res.mjs +22 -0
- package/src/bindings/EventSource.res +8 -1
- package/src/bindings/EventSource.res.mjs +8 -1
- package/src/bindings/Express.res +1 -0
- package/src/bindings/Hrtime.res +14 -1
- package/src/bindings/Hrtime.res.mjs +22 -2
- package/src/bindings/Hrtime.resi +4 -0
- package/src/bindings/Lodash.res +0 -1
- package/src/bindings/NodeJs.res +49 -3
- package/src/bindings/NodeJs.res.mjs +11 -3
- package/src/bindings/Pino.res +24 -10
- package/src/bindings/Pino.res.mjs +14 -8
- package/src/bindings/Postgres.gen.ts +8 -0
- package/src/bindings/Postgres.res +5 -1
- package/src/bindings/Postgres.res.d.mts +5 -0
- package/src/bindings/PromClient.res +0 -10
- package/src/bindings/PromClient.res.mjs +0 -3
- package/src/bindings/Vitest.res +142 -0
- package/src/bindings/Vitest.res.mjs +9 -0
- package/src/bindings/WebSocket.res +27 -0
- package/src/bindings/WebSocket.res.mjs +2 -0
- package/src/bindings/Yargs.res +8 -0
- package/src/bindings/Yargs.res.mjs +2 -0
- package/src/db/EntityHistory.res +7 -7
- package/src/db/EntityHistory.res.mjs +9 -9
- package/src/db/InternalTable.res +59 -111
- package/src/db/InternalTable.res.mjs +73 -104
- package/src/db/Table.res +27 -8
- package/src/db/Table.res.mjs +25 -14
- package/src/sources/Evm.res +84 -0
- package/src/sources/Evm.res.mjs +105 -0
- package/src/sources/EvmChain.res +94 -0
- package/src/sources/EvmChain.res.mjs +60 -0
- package/src/sources/Fuel.res +19 -34
- package/src/sources/Fuel.res.mjs +34 -16
- package/src/sources/FuelSDK.res +38 -0
- package/src/sources/FuelSDK.res.mjs +29 -0
- package/src/sources/HyperFuel.res +2 -2
- package/src/sources/HyperFuel.resi +1 -1
- package/src/sources/HyperFuelClient.res +2 -2
- package/src/sources/HyperFuelSource.res +33 -13
- package/src/sources/HyperFuelSource.res.mjs +24 -16
- package/src/sources/HyperSync.res +36 -6
- package/src/sources/HyperSync.res.mjs +9 -7
- package/src/sources/HyperSync.resi +4 -0
- package/src/sources/HyperSyncClient.res +1 -1
- package/src/sources/HyperSyncHeightStream.res +47 -116
- package/src/sources/HyperSyncHeightStream.res.mjs +46 -73
- package/src/sources/HyperSyncSource.res +118 -139
- package/src/sources/HyperSyncSource.res.mjs +104 -121
- package/src/sources/Rpc.res +86 -14
- package/src/sources/Rpc.res.mjs +101 -9
- package/src/sources/RpcSource.res +621 -364
- package/src/sources/RpcSource.res.mjs +843 -410
- package/src/sources/RpcWebSocketHeightStream.res +181 -0
- package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
- package/src/sources/Source.res +7 -5
- package/src/sources/SourceManager.res +325 -225
- package/src/sources/SourceManager.res.mjs +314 -171
- package/src/sources/SourceManager.resi +17 -6
- package/src/sources/Svm.res +81 -0
- package/src/sources/Svm.res.mjs +90 -0
- package/src/tui/Tui.res +247 -0
- package/src/tui/Tui.res.mjs +337 -0
- package/src/tui/bindings/Ink.res +371 -0
- package/src/tui/bindings/Ink.res.mjs +72 -0
- package/src/tui/bindings/Style.res +123 -0
- package/src/tui/bindings/Style.res.mjs +2 -0
- package/src/tui/components/BufferedProgressBar.res +40 -0
- package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
- package/src/tui/components/CustomHooks.res +122 -0
- package/src/tui/components/CustomHooks.res.mjs +179 -0
- package/src/tui/components/Messages.res +41 -0
- package/src/tui/components/Messages.res.mjs +75 -0
- package/src/tui/components/SyncETA.res +174 -0
- package/src/tui/components/SyncETA.res.mjs +263 -0
- package/src/tui/components/TuiData.res +47 -0
- package/src/tui/components/TuiData.res.mjs +34 -0
- package/svm.schema.json +112 -0
- package/bin.js +0 -48
- package/src/EventRegister.res +0 -241
- package/src/EventRegister.res.mjs +0 -240
- package/src/bindings/Ethers.gen.ts +0 -14
- package/src/bindings/Ethers.res +0 -204
- package/src/bindings/Ethers.res.mjs +0 -130
- /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
|
@@ -9,6 +9,7 @@ import * as $$Promise from "../bindings/Promise.res.mjs";
|
|
|
9
9
|
import * as HyperFuel from "./HyperFuel.res.mjs";
|
|
10
10
|
import * as HyperSync from "./HyperSync.res.mjs";
|
|
11
11
|
import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
|
|
12
|
+
import * as Prometheus from "../Prometheus.res.mjs";
|
|
12
13
|
import * as Belt_Option from "rescript/lib/es6/belt_Option.js";
|
|
13
14
|
import * as EventRouter from "./EventRouter.res.mjs";
|
|
14
15
|
import * as ErrorHandling from "../ErrorHandling.res.mjs";
|
|
@@ -185,8 +186,9 @@ function memoGetSelectionConfig(chain) {
|
|
|
185
186
|
function make(param) {
|
|
186
187
|
var endpointUrl = param.endpointUrl;
|
|
187
188
|
var chain = param.chain;
|
|
189
|
+
var name = "HyperFuel";
|
|
188
190
|
var getSelectionConfig = memoGetSelectionConfig(chain);
|
|
189
|
-
var getItemsOrThrow = async function (fromBlock, toBlock, addressesByContractName, indexingContracts,
|
|
191
|
+
var getItemsOrThrow = async function (fromBlock, toBlock, addressesByContractName, indexingContracts, knownHeight, param, selection, retry, logger) {
|
|
190
192
|
var mkLogAndRaise = function (extra, extra$1) {
|
|
191
193
|
return ErrorHandling.mkLogAndRaise(logger, extra, extra$1);
|
|
192
194
|
};
|
|
@@ -194,6 +196,7 @@ function make(param) {
|
|
|
194
196
|
var selectionConfig = getSelectionConfig(selection);
|
|
195
197
|
var recieptsSelection = selectionConfig.getRecieptsSelection(addressesByContractName);
|
|
196
198
|
var startFetchingBatchTimeRef = Hrtime.makeTimer();
|
|
199
|
+
Prometheus.SourceRequestCount.increment(name, chain, "getLogs");
|
|
197
200
|
var pageUnsafe;
|
|
198
201
|
try {
|
|
199
202
|
pageUnsafe = await HyperFuel.GetLogs.query(endpointUrl, fromBlock, toBlock, recieptsSelection);
|
|
@@ -221,7 +224,7 @@ function make(param) {
|
|
|
221
224
|
_1: {
|
|
222
225
|
TAG: "FailedGettingItems",
|
|
223
226
|
exn: null,
|
|
224
|
-
attemptedToBlock: Belt_Option.getWithDefault(toBlock,
|
|
227
|
+
attemptedToBlock: Belt_Option.getWithDefault(toBlock, knownHeight),
|
|
225
228
|
retry: tmp
|
|
226
229
|
},
|
|
227
230
|
Error: new Error()
|
|
@@ -232,7 +235,7 @@ function make(param) {
|
|
|
232
235
|
_1: {
|
|
233
236
|
TAG: "FailedGettingItems",
|
|
234
237
|
exn: error,
|
|
235
|
-
attemptedToBlock: Belt_Option.getWithDefault(toBlock,
|
|
238
|
+
attemptedToBlock: Belt_Option.getWithDefault(toBlock, knownHeight),
|
|
236
239
|
retry: {
|
|
237
240
|
TAG: "WithBackoff",
|
|
238
241
|
message: "Unexpected issue while fetching events from HyperFuel client. Attempt a retry.",
|
|
@@ -242,8 +245,8 @@ function make(param) {
|
|
|
242
245
|
Error: new Error()
|
|
243
246
|
};
|
|
244
247
|
}
|
|
245
|
-
var pageFetchTime = Hrtime.
|
|
246
|
-
var
|
|
248
|
+
var pageFetchTime = Hrtime.toSecondsFloat(Hrtime.timeSince(startFetchingBatchTimeRef));
|
|
249
|
+
var knownHeight$1 = pageUnsafe.archiveHeight;
|
|
247
250
|
var heighestBlockQueried = pageUnsafe.nextBlock - 1 | 0;
|
|
248
251
|
var match = Belt_Array.get(pageUnsafe.items, pageUnsafe.items.length - 1 | 0);
|
|
249
252
|
var lastBlockQueriedPromise;
|
|
@@ -392,22 +395,22 @@ function make(param) {
|
|
|
392
395
|
}
|
|
393
396
|
};
|
|
394
397
|
}));
|
|
395
|
-
var parsingTimeElapsed = Hrtime.
|
|
398
|
+
var parsingTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(parsingTimeRef));
|
|
396
399
|
var rangeLastBlock = await lastBlockQueriedPromise;
|
|
397
400
|
var reorgGuard = {
|
|
398
401
|
rangeLastBlock: rangeLastBlock,
|
|
399
402
|
prevRangeLastBlock: undefined
|
|
400
403
|
};
|
|
401
|
-
var totalTimeElapsed = Hrtime.
|
|
402
|
-
var stats_parsing$unknowntime$unknown$
|
|
403
|
-
var stats_page$unknownfetch$unknowntime$unknown$
|
|
404
|
+
var totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(totalTimeRef));
|
|
405
|
+
var stats_parsing$unknowntime$unknown$lpars$rpar = parsingTimeElapsed;
|
|
406
|
+
var stats_page$unknownfetch$unknowntime$unknown$lpars$rpar = pageFetchTime;
|
|
404
407
|
var stats = {
|
|
405
|
-
"total time elapsed (
|
|
406
|
-
"parsing time (
|
|
407
|
-
"page fetch time (
|
|
408
|
+
"total time elapsed (s)": totalTimeElapsed,
|
|
409
|
+
"parsing time (s)": stats_parsing$unknowntime$unknown$lpars$rpar,
|
|
410
|
+
"page fetch time (s)": stats_page$unknownfetch$unknowntime$unknown$lpars$rpar
|
|
408
411
|
};
|
|
409
412
|
return {
|
|
410
|
-
|
|
413
|
+
knownHeight: knownHeight$1,
|
|
411
414
|
reorgGuard: reorgGuard,
|
|
412
415
|
parsedQueueItems: parsedQueueItems,
|
|
413
416
|
fromBlockQueried: fromBlock,
|
|
@@ -421,14 +424,19 @@ function make(param) {
|
|
|
421
424
|
};
|
|
422
425
|
var jsonApiClient = Rest.client(endpointUrl, undefined);
|
|
423
426
|
return {
|
|
424
|
-
name:
|
|
427
|
+
name: name,
|
|
425
428
|
sourceFor: "Sync",
|
|
426
429
|
chain: chain,
|
|
427
430
|
poweredByHyperSync: true,
|
|
428
431
|
pollingInterval: 100,
|
|
429
432
|
getBlockHashes: getBlockHashes,
|
|
430
|
-
getHeightOrThrow: (function () {
|
|
431
|
-
|
|
433
|
+
getHeightOrThrow: (async function () {
|
|
434
|
+
var timerRef = Hrtime.makeTimer();
|
|
435
|
+
var height = await Rest.$$fetch(HyperFuel.heightRoute, undefined, jsonApiClient);
|
|
436
|
+
var seconds = Hrtime.toSecondsFloat(Hrtime.timeSince(timerRef));
|
|
437
|
+
Prometheus.SourceRequestCount.increment(name, chain, "getHeight");
|
|
438
|
+
Prometheus.SourceRequestCount.addSeconds(name, chain, "getHeight", seconds);
|
|
439
|
+
return height;
|
|
432
440
|
}),
|
|
433
441
|
getItemsOrThrow: getItemsOrThrow
|
|
434
442
|
};
|
|
@@ -114,7 +114,7 @@ module GetLogs = {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
//Topics can be nullable and still need to be filtered
|
|
117
|
-
let logUnsanitized: Log.t = event.log->Utils.magic
|
|
117
|
+
let logUnsanitized: Log.t = event.log->(Utils.magic: HyperSyncClient.ResponseTypes.log => Log.t)
|
|
118
118
|
let topics = event.log.topics->Option.getUnsafe->Array.keepMap(Js.Nullable.toOption)
|
|
119
119
|
let address = event.log.address->Option.getUnsafe
|
|
120
120
|
let log = {
|
|
@@ -125,8 +125,14 @@ module GetLogs = {
|
|
|
125
125
|
|
|
126
126
|
{
|
|
127
127
|
log,
|
|
128
|
-
block: event.block->
|
|
129
|
-
|
|
128
|
+
block: event.block->(
|
|
129
|
+
Utils.magic: option<
|
|
130
|
+
HyperSyncClient.ResponseTypes.block,
|
|
131
|
+
> => HyperSyncClient.ResponseTypes.block
|
|
132
|
+
),
|
|
133
|
+
transaction: event.transaction->(
|
|
134
|
+
Utils.magic: option<HyperSyncClient.ResponseTypes.transaction> => Internal.eventTransaction
|
|
135
|
+
),
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
138
|
|
|
@@ -245,6 +251,8 @@ module BlockData = {
|
|
|
245
251
|
~apiToken,
|
|
246
252
|
~fromBlock,
|
|
247
253
|
~toBlock,
|
|
254
|
+
~sourceName,
|
|
255
|
+
~chainId,
|
|
248
256
|
~logger,
|
|
249
257
|
): queryResponse<array<ReorgDetection.blockDataWithTimestamp>> => {
|
|
250
258
|
let body = makeRequestBody(~fromBlock, ~toBlock)
|
|
@@ -258,6 +266,7 @@ module BlockData = {
|
|
|
258
266
|
},
|
|
259
267
|
)
|
|
260
268
|
|
|
269
|
+
Prometheus.SourceRequestCount.increment(~sourceName, ~chainId, ~method="getBlockHashes")
|
|
261
270
|
let maybeSuccessfulRes = switch await Time.retryAsyncWithExponentialBackOff(() =>
|
|
262
271
|
HyperSyncJsonApi.queryRoute->Rest.fetch(
|
|
263
272
|
{
|
|
@@ -281,7 +290,15 @@ module BlockData = {
|
|
|
281
290
|
`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.`,
|
|
282
291
|
)
|
|
283
292
|
await Time.resolvePromiseAfterDelay(~delayMilliseconds)
|
|
284
|
-
await queryBlockData(
|
|
293
|
+
await queryBlockData(
|
|
294
|
+
~serverUrl,
|
|
295
|
+
~apiToken,
|
|
296
|
+
~fromBlock,
|
|
297
|
+
~toBlock,
|
|
298
|
+
~sourceName,
|
|
299
|
+
~chainId,
|
|
300
|
+
~logger,
|
|
301
|
+
)
|
|
285
302
|
}
|
|
286
303
|
| Some(res) =>
|
|
287
304
|
switch res->convertResponse {
|
|
@@ -292,6 +309,8 @@ module BlockData = {
|
|
|
292
309
|
~apiToken,
|
|
293
310
|
~fromBlock=res.nextBlock,
|
|
294
311
|
~toBlock,
|
|
312
|
+
~sourceName,
|
|
313
|
+
~chainId,
|
|
295
314
|
~logger,
|
|
296
315
|
)
|
|
297
316
|
restRes->Result.map(rest => datas->Array.concat(rest))
|
|
@@ -301,7 +320,14 @@ module BlockData = {
|
|
|
301
320
|
}
|
|
302
321
|
}
|
|
303
322
|
|
|
304
|
-
let queryBlockDataMulti = async (
|
|
323
|
+
let queryBlockDataMulti = async (
|
|
324
|
+
~serverUrl,
|
|
325
|
+
~apiToken,
|
|
326
|
+
~blockNumbers,
|
|
327
|
+
~sourceName,
|
|
328
|
+
~chainId,
|
|
329
|
+
~logger,
|
|
330
|
+
) => {
|
|
305
331
|
switch blockNumbers->Array.get(0) {
|
|
306
332
|
| None => Ok([])
|
|
307
333
|
| Some(firstBlock) => {
|
|
@@ -328,6 +354,8 @@ module BlockData = {
|
|
|
328
354
|
~toBlock=toBlock.contents,
|
|
329
355
|
~serverUrl,
|
|
330
356
|
~apiToken,
|
|
357
|
+
~sourceName,
|
|
358
|
+
~chainId,
|
|
331
359
|
~logger,
|
|
332
360
|
)
|
|
333
361
|
let filtered = res->Result.map(datas => {
|
|
@@ -346,12 +374,14 @@ module BlockData = {
|
|
|
346
374
|
}
|
|
347
375
|
}
|
|
348
376
|
|
|
349
|
-
let queryBlockData = (~serverUrl, ~apiToken, ~blockNumber, ~logger) =>
|
|
377
|
+
let queryBlockData = (~serverUrl, ~apiToken, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
|
|
350
378
|
BlockData.queryBlockData(
|
|
351
379
|
~serverUrl,
|
|
352
380
|
~apiToken,
|
|
353
381
|
~fromBlock=blockNumber,
|
|
354
382
|
~toBlock=blockNumber,
|
|
383
|
+
~sourceName,
|
|
384
|
+
~chainId,
|
|
355
385
|
~logger,
|
|
356
386
|
)->Promise.thenResolve(res => res->Result.map(res => res->Array.get(0)))
|
|
357
387
|
let queryBlockDataMulti = BlockData.queryBlockDataMulti
|
|
@@ -7,6 +7,7 @@ import * as $$BigInt from "../bindings/BigInt.res.mjs";
|
|
|
7
7
|
import * as Js_exn from "rescript/lib/es6/js_exn.js";
|
|
8
8
|
import * as Logging from "../Logging.res.mjs";
|
|
9
9
|
import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
|
|
10
|
+
import * as Prometheus from "../Prometheus.res.mjs";
|
|
10
11
|
import * as Belt_Option from "rescript/lib/es6/belt_Option.js";
|
|
11
12
|
import * as Belt_Result from "rescript/lib/es6/belt_Result.js";
|
|
12
13
|
import * as Caml_option from "rescript/lib/es6/caml_option.js";
|
|
@@ -226,13 +227,14 @@ function convertResponse(res) {
|
|
|
226
227
|
})));
|
|
227
228
|
}
|
|
228
229
|
|
|
229
|
-
async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger) {
|
|
230
|
+
async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, sourceName, chainId, logger) {
|
|
230
231
|
var body = makeRequestBody$1(fromBlock, toBlock);
|
|
231
232
|
var logger$1 = Logging.createChildFrom(logger, {
|
|
232
233
|
logType: "HyperSync get block hash query",
|
|
233
234
|
fromBlock: fromBlock,
|
|
234
235
|
toBlock: toBlock
|
|
235
236
|
});
|
|
237
|
+
Prometheus.SourceRequestCount.increment(sourceName, chainId, "getBlockHashes");
|
|
236
238
|
var maybeSuccessfulRes;
|
|
237
239
|
var exit = 0;
|
|
238
240
|
var res;
|
|
@@ -260,7 +262,7 @@ async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger) {
|
|
|
260
262
|
return err;
|
|
261
263
|
}
|
|
262
264
|
var datas = err._0;
|
|
263
|
-
var restRes = await queryBlockData(serverUrl, apiToken, maybeSuccessfulRes.nextBlock, toBlock, logger$1);
|
|
265
|
+
var restRes = await queryBlockData(serverUrl, apiToken, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1);
|
|
264
266
|
return Belt_Result.map(restRes, (function (rest) {
|
|
265
267
|
return Belt_Array.concat(datas, rest);
|
|
266
268
|
}));
|
|
@@ -270,10 +272,10 @@ async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger) {
|
|
|
270
272
|
});
|
|
271
273
|
Logging.childInfo(logger$2, "Block #" + String(fromBlock) + " 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 " + String(100) + "ms.");
|
|
272
274
|
await Time.resolvePromiseAfterDelay(100);
|
|
273
|
-
return await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger$2);
|
|
275
|
+
return await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, sourceName, chainId, logger$2);
|
|
274
276
|
}
|
|
275
277
|
|
|
276
|
-
async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, logger) {
|
|
278
|
+
async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, sourceName, chainId, logger) {
|
|
277
279
|
var firstBlock = Belt_Array.get(blockNumbers, 0);
|
|
278
280
|
if (firstBlock === undefined) {
|
|
279
281
|
return {
|
|
@@ -297,7 +299,7 @@ async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, logger) {
|
|
|
297
299
|
if ((toBlock - fromBlock | 0) > 1000) {
|
|
298
300
|
Js_exn.raiseError("Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: " + String(fromBlock) + "-" + String(toBlock));
|
|
299
301
|
}
|
|
300
|
-
var res = await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger);
|
|
302
|
+
var res = await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, sourceName, chainId, logger);
|
|
301
303
|
var filtered = Belt_Result.map(res, (function (datas) {
|
|
302
304
|
return Belt_Array.keep(datas, (function (data) {
|
|
303
305
|
return set.delete(data.blockNumber);
|
|
@@ -309,8 +311,8 @@ async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, logger) {
|
|
|
309
311
|
return filtered;
|
|
310
312
|
}
|
|
311
313
|
|
|
312
|
-
function queryBlockData$1(serverUrl, apiToken, blockNumber, logger) {
|
|
313
|
-
return queryBlockData(serverUrl, apiToken, blockNumber, blockNumber, logger).then(function (res) {
|
|
314
|
+
function queryBlockData$1(serverUrl, apiToken, blockNumber, sourceName, chainId, logger) {
|
|
315
|
+
return queryBlockData(serverUrl, apiToken, blockNumber, blockNumber, sourceName, chainId, logger).then(function (res) {
|
|
314
316
|
return Belt_Result.map(res, (function (res) {
|
|
315
317
|
return Belt_Array.get(res, 0);
|
|
316
318
|
}));
|
|
@@ -56,6 +56,8 @@ let queryBlockData: (
|
|
|
56
56
|
~serverUrl: string,
|
|
57
57
|
~apiToken: string,
|
|
58
58
|
~blockNumber: int,
|
|
59
|
+
~sourceName: string,
|
|
60
|
+
~chainId: int,
|
|
59
61
|
~logger: Pino.t,
|
|
60
62
|
) => promise<queryResponse<option<ReorgDetection.blockDataWithTimestamp>>>
|
|
61
63
|
|
|
@@ -63,6 +65,8 @@ let queryBlockDataMulti: (
|
|
|
63
65
|
~serverUrl: string,
|
|
64
66
|
~apiToken: string,
|
|
65
67
|
~blockNumbers: array<int>,
|
|
68
|
+
~sourceName: string,
|
|
69
|
+
~chainId: int,
|
|
66
70
|
~logger: Pino.t,
|
|
67
71
|
) => promise<queryResponse<array<ReorgDetection.blockDataWithTimestamp>>>
|
|
68
72
|
|
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Pure
|
|
2
|
+
Pure subscription-based implementation of the HyperSync height stream.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
timeoutIdRef
|
|
9
|
-
eventsourceRef: ref<option<EventSource.t>>,
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
let make = (~hyperSyncUrl, ~apiToken) => {
|
|
13
|
-
/**
|
|
14
|
-
On every successful ping or height event, clear the timeout and set a new one.
|
|
5
|
+
let subscribe = (~hyperSyncUrl, ~apiToken, ~chainId, ~onHeight: int => unit): (unit => unit) => {
|
|
6
|
+
let eventsourceRef = ref(None)
|
|
7
|
+
// Timeout doesn't do anything for initialization
|
|
8
|
+
let timeoutIdRef = ref(Js.Global.setTimeout(() => (), 0))
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let rec updateTimeoutId = (
|
|
19
|
-
~eventsourceRef: ref<option<EventSource.t>>,
|
|
20
|
-
~timeoutIdRef: ref<Js.Global.timeoutId>,
|
|
21
|
-
~hyperSyncUrl,
|
|
22
|
-
~apiToken,
|
|
23
|
-
~heightRef: ref<int>,
|
|
24
|
-
~errorRef: ref<option<string>>,
|
|
25
|
-
) => {
|
|
10
|
+
// On every successful ping or height event, clear the timeout and set a new one.
|
|
11
|
+
// If the timeout lapses, close and reconnect the EventSource.
|
|
12
|
+
let rec updateTimeoutId = () => {
|
|
26
13
|
timeoutIdRef.contents->Js.Global.clearTimeout
|
|
27
14
|
|
|
28
15
|
// Should receive a ping at least every 5s, so 15s is a safe margin
|
|
@@ -34,31 +21,15 @@ let make = (~hyperSyncUrl, ~apiToken) => {
|
|
|
34
21
|
"url": hyperSyncUrl,
|
|
35
22
|
"staleTimeMillis": staleTimeMillis,
|
|
36
23
|
})
|
|
37
|
-
refreshEventSource(
|
|
38
|
-
~eventsourceRef,
|
|
39
|
-
~hyperSyncUrl,
|
|
40
|
-
~apiToken,
|
|
41
|
-
~heightRef,
|
|
42
|
-
~errorRef,
|
|
43
|
-
~timeoutIdRef,
|
|
44
|
-
)
|
|
24
|
+
refreshEventSource()
|
|
45
25
|
}, staleTimeMillis)
|
|
46
26
|
|
|
47
27
|
timeoutIdRef := newTimeoutId
|
|
48
28
|
}
|
|
49
|
-
and
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
*/
|
|
54
|
-
refreshEventSource = (
|
|
55
|
-
~eventsourceRef: ref<option<EventSource.t>>,
|
|
56
|
-
~hyperSyncUrl,
|
|
57
|
-
~apiToken,
|
|
58
|
-
~heightRef: ref<int>,
|
|
59
|
-
~errorRef: ref<option<string>>,
|
|
60
|
-
~timeoutIdRef: ref<Js.Global.timeoutId>,
|
|
61
|
-
) => {
|
|
29
|
+
// Instantiate a new EventSource and set it to the shared refs.
|
|
30
|
+
// Add the necessary event listeners, handle errors
|
|
31
|
+
// and update the timeout.
|
|
32
|
+
and refreshEventSource = () => {
|
|
62
33
|
// Close the old EventSource if it exists (on a new connection after timeout)
|
|
63
34
|
switch eventsourceRef.contents {
|
|
64
35
|
| Some(es) => es->EventSource.close
|
|
@@ -69,17 +40,25 @@ let make = (~hyperSyncUrl, ~apiToken) => {
|
|
|
69
40
|
let es = EventSource.create(
|
|
70
41
|
~url=`${hyperSyncUrl}/height/sse`,
|
|
71
42
|
~options={
|
|
72
|
-
|
|
73
|
-
(
|
|
74
|
-
|
|
75
|
-
|
|
43
|
+
fetch: (url, ~args) => {
|
|
44
|
+
EventSource.Fetch.fetch(
|
|
45
|
+
url,
|
|
46
|
+
~args={
|
|
47
|
+
...args,
|
|
48
|
+
headers: Js.Dict.fromArray([
|
|
49
|
+
("Authorization", `Bearer ${apiToken}`),
|
|
50
|
+
("User-Agent", userAgent),
|
|
51
|
+
]),
|
|
52
|
+
},
|
|
53
|
+
)
|
|
54
|
+
},
|
|
76
55
|
},
|
|
77
56
|
)
|
|
78
57
|
|
|
79
58
|
// Set the new EventSource to the shared ref
|
|
80
59
|
eventsourceRef := Some(es)
|
|
81
60
|
// Update the timeout in case connection goes stale
|
|
82
|
-
updateTimeoutId(
|
|
61
|
+
updateTimeoutId()
|
|
83
62
|
|
|
84
63
|
es->EventSource.onopen(_ => {
|
|
85
64
|
Logging.trace({"msg": "SSE connection opened for height stream", "url": hyperSyncUrl})
|
|
@@ -90,90 +69,42 @@ let make = (~hyperSyncUrl, ~apiToken) => {
|
|
|
90
69
|
"msg": "EventSource error",
|
|
91
70
|
"error": error->Js.Exn.message,
|
|
92
71
|
})
|
|
93
|
-
// On errors, set the error ref
|
|
94
|
-
// so that getHeight can raise an error
|
|
95
|
-
errorRef :=
|
|
96
|
-
Some(error->Js.Exn.message->Belt.Option.getWithDefault("Unexpected no error.message"))
|
|
97
72
|
})
|
|
98
73
|
|
|
99
74
|
es->EventSource.addEventListener("ping", _event => {
|
|
100
75
|
// ping lets us know from the server that the connection is still alive
|
|
101
|
-
// and that the height hasn't updated for
|
|
76
|
+
// and that the height hasn't updated for 5 seconds
|
|
102
77
|
// update the timeout on each successful ping received
|
|
103
|
-
updateTimeoutId(
|
|
104
|
-
~eventsourceRef,
|
|
105
|
-
~timeoutIdRef,
|
|
106
|
-
~hyperSyncUrl,
|
|
107
|
-
~apiToken,
|
|
108
|
-
~heightRef,
|
|
109
|
-
~errorRef,
|
|
110
|
-
)
|
|
111
|
-
// reset the error ref, since we had a successful ping
|
|
112
|
-
errorRef := None
|
|
78
|
+
updateTimeoutId()
|
|
113
79
|
})
|
|
114
80
|
|
|
115
81
|
es->EventSource.addEventListener("height", event => {
|
|
116
82
|
switch event.data->Belt.Int.fromString {
|
|
117
83
|
| Some(height) =>
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
~
|
|
122
|
-
~
|
|
123
|
-
~hyperSyncUrl,
|
|
124
|
-
~apiToken,
|
|
125
|
-
~heightRef,
|
|
126
|
-
~errorRef,
|
|
84
|
+
// Track the SSE height event
|
|
85
|
+
Prometheus.SourceRequestCount.increment(
|
|
86
|
+
~sourceName="HyperSync",
|
|
87
|
+
~chainId,
|
|
88
|
+
~method="heightStream",
|
|
127
89
|
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
errorRef := Some("Height was not a number in event.data")
|
|
90
|
+
// On a successful height event, update the timeout
|
|
91
|
+
updateTimeoutId()
|
|
92
|
+
// Call the callback with the new height
|
|
93
|
+
onHeight(height)
|
|
94
|
+
| None => Logging.trace({"msg": "Height was not a number in event.data", "data": event.data})
|
|
134
95
|
}
|
|
135
96
|
})
|
|
136
97
|
}
|
|
137
98
|
|
|
138
|
-
//
|
|
99
|
+
// Start the EventSource connection
|
|
100
|
+
refreshEventSource()
|
|
139
101
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
~hyperSyncUrl,
|
|
148
|
-
~apiToken,
|
|
149
|
-
~heightRef,
|
|
150
|
-
~errorRef,
|
|
151
|
-
~timeoutIdRef,
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
{
|
|
155
|
-
heightRef,
|
|
156
|
-
errorRef,
|
|
157
|
-
timeoutIdRef,
|
|
158
|
-
eventsourceRef,
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
let getHeight = async (t: t) => {
|
|
163
|
-
while t.heightRef.contents == 0 && t.errorRef.contents == None {
|
|
164
|
-
// Poll internally until height is over 0
|
|
165
|
-
await Utils.delay(200)
|
|
166
|
-
}
|
|
167
|
-
switch t.errorRef.contents {
|
|
168
|
-
| None => t.heightRef.contents
|
|
169
|
-
| Some(error) => Js.Exn.raiseError(error)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
let close = t => {
|
|
174
|
-
t.timeoutIdRef.contents->Js.Global.clearTimeout
|
|
175
|
-
switch t.eventsourceRef.contents {
|
|
176
|
-
| Some(es) => es->EventSource.close
|
|
177
|
-
| None => ()
|
|
102
|
+
// Return unsubscribe function
|
|
103
|
+
() => {
|
|
104
|
+
timeoutIdRef.contents->Js.Global.clearTimeout
|
|
105
|
+
switch eventsourceRef.contents {
|
|
106
|
+
| Some(es) => es->EventSource.close
|
|
107
|
+
| None => ()
|
|
108
|
+
}
|
|
178
109
|
}
|
|
179
110
|
}
|