envio 3.0.2 → 3.1.0-rc.1
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 +0 -1
- package/evm.schema.json +15 -8
- package/fuel.schema.json +19 -12
- package/index.d.ts +0 -2
- package/package.json +6 -7
- package/rescript.json +1 -1
- package/src/Batch.res +4 -214
- package/src/Batch.res.mjs +6 -165
- package/src/ChainFetcher.res +12 -28
- package/src/ChainFetcher.res.mjs +8 -17
- package/src/ChainManager.res +10 -9
- package/src/ChainManager.res.mjs +6 -10
- package/src/Config.res +9 -25
- package/src/Config.res.mjs +17 -27
- package/src/Core.res +7 -0
- package/src/Ctx.res +1 -0
- package/src/Env.res +0 -8
- package/src/Env.res.mjs +0 -6
- package/src/EventConfigBuilder.res +13 -123
- package/src/EventConfigBuilder.res.mjs +6 -73
- package/src/EventProcessing.res +5 -29
- package/src/EventProcessing.res.mjs +11 -20
- package/src/EventUtils.res +0 -27
- package/src/EventUtils.res.mjs +0 -24
- package/src/FetchState.res +2 -15
- package/src/FetchState.res.mjs +3 -18
- package/src/GlobalState.res +26 -39
- package/src/GlobalState.res.mjs +12 -40
- package/src/HandlerLoader.res +6 -5
- package/src/HandlerLoader.res.mjs +27 -9
- package/src/HandlerRegister.res +1 -12
- package/src/HandlerRegister.res.mjs +1 -6
- package/src/HandlerRegister.resi +1 -1
- package/src/Hasura.res +96 -32
- package/src/Hasura.res.mjs +93 -38
- package/src/InMemoryStore.res +205 -45
- package/src/InMemoryStore.res.mjs +157 -40
- package/src/InMemoryTable.res +165 -249
- package/src/InMemoryTable.res.mjs +156 -227
- package/src/Internal.res +10 -34
- package/src/Internal.res.mjs +9 -3
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +5 -5
- package/src/LogSelection.res +15 -19
- package/src/LogSelection.res.mjs +5 -6
- package/src/Main.res +4 -6
- package/src/Main.res.mjs +26 -15
- package/src/Persistence.res +7 -132
- package/src/Persistence.res.mjs +1 -102
- package/src/PgStorage.res +57 -40
- package/src/PgStorage.res.mjs +60 -34
- package/src/ReorgDetection.res +35 -58
- package/src/ReorgDetection.res.mjs +21 -29
- package/src/SimulateItems.res.mjs +21 -3
- package/src/Sink.res +2 -2
- package/src/Sink.res.mjs +1 -1
- package/src/TableIndices.res +9 -2
- package/src/TableIndices.res.mjs +7 -1
- package/src/TestIndexer.res +53 -60
- package/src/TestIndexer.res.mjs +77 -63
- package/src/TestIndexerProxyStorage.res +4 -14
- package/src/TestIndexerProxyStorage.res.mjs +1 -5
- package/src/UserContext.res +2 -4
- package/src/UserContext.res.mjs +4 -5
- package/src/Utils.res +0 -2
- package/src/Utils.res.mjs +0 -3
- package/src/bindings/ClickHouse.res +45 -38
- package/src/bindings/ClickHouse.res.mjs +16 -17
- package/src/bindings/Vitest.res +3 -0
- package/src/db/InternalTable.res +59 -18
- package/src/db/InternalTable.res.mjs +82 -51
- package/src/db/Table.res +9 -2
- package/src/db/Table.res.mjs +10 -7
- package/src/sources/EnvioApiClient.res +15 -0
- package/src/sources/EnvioApiClient.res.mjs +24 -0
- package/src/sources/EvmChain.res +32 -10
- package/src/sources/EvmChain.res.mjs +31 -5
- package/src/sources/HyperFuelSource.res +15 -58
- package/src/sources/HyperFuelSource.res.mjs +20 -39
- package/src/sources/HyperSync.res +54 -100
- package/src/sources/HyperSync.res.mjs +67 -96
- package/src/sources/HyperSync.resi +4 -22
- package/src/sources/HyperSyncClient.res +70 -247
- package/src/sources/HyperSyncClient.res.mjs +47 -46
- package/src/sources/HyperSyncSource.res +94 -166
- package/src/sources/HyperSyncSource.res.mjs +100 -127
- package/src/sources/RpcSource.res +43 -22
- package/src/sources/RpcSource.res.mjs +50 -35
- package/src/sources/SimulateSource.res +1 -7
- package/src/sources/SimulateSource.res.mjs +1 -7
- package/src/sources/Source.res +10 -1
- package/src/sources/Source.res.mjs +3 -0
- package/src/sources/SourceManager.res +177 -8
- package/src/sources/SourceManager.res.mjs +141 -3
- package/src/sources/SourceManager.resi +19 -0
- package/src/tui/Tui.res +44 -6
- package/src/tui/Tui.res.mjs +56 -8
- package/src/tui/components/TuiData.res +3 -0
- package/svm.schema.json +11 -4
- package/src/sources/HyperSyncJsonApi.res +0 -390
- package/src/sources/HyperSyncJsonApi.res.mjs +0 -237
|
@@ -225,7 +225,6 @@ let make = ({chain, endpointUrl}: options): t => {
|
|
|
225
225
|
~retry,
|
|
226
226
|
~logger,
|
|
227
227
|
) => {
|
|
228
|
-
let mkLogAndRaise = ErrorHandling.mkLogAndRaise(~logger, ...)
|
|
229
228
|
let totalTimeRef = Hrtime.makeTimer()
|
|
230
229
|
|
|
231
230
|
let selectionConfig = getSelectionConfig(selection)
|
|
@@ -299,55 +298,6 @@ let make = ({chain, endpointUrl}: options): t => {
|
|
|
299
298
|
//In the query
|
|
300
299
|
let heighestBlockQueried = pageUnsafe.nextBlock - 1
|
|
301
300
|
|
|
302
|
-
let lastBlockQueriedPromise = // switch pageUnsafe.rollbackGuard {
|
|
303
|
-
// //In the case a rollbackGuard is returned (this only happens at the head for unconfirmed blocks)
|
|
304
|
-
// //use these values
|
|
305
|
-
// | Some({blockNumber, timestamp, hash}) =>
|
|
306
|
-
// {
|
|
307
|
-
// ReorgDetection.blockNumber,
|
|
308
|
-
// blockTimestamp: timestamp,
|
|
309
|
-
// blockHash: hash,
|
|
310
|
-
// }->Promise.resolve
|
|
311
|
-
// | None =>
|
|
312
|
-
//The optional block and timestamp of the last item returned by the query
|
|
313
|
-
//(Optional in the case that there are no logs returned in the query)
|
|
314
|
-
switch pageUnsafe.items->Belt.Array.get(pageUnsafe.items->Belt.Array.length - 1) {
|
|
315
|
-
| Some({block}) if block.height == heighestBlockQueried =>
|
|
316
|
-
//If the last log item in the current page is equal to the
|
|
317
|
-
//heighest block acounted for in the query. Simply return this
|
|
318
|
-
//value without making an extra query
|
|
319
|
-
|
|
320
|
-
(
|
|
321
|
-
{
|
|
322
|
-
blockNumber: block.height,
|
|
323
|
-
blockTimestamp: block.time,
|
|
324
|
-
blockHash: block.id,
|
|
325
|
-
}: ReorgDetection.blockDataWithTimestamp
|
|
326
|
-
)->Promise.resolve
|
|
327
|
-
//If it does not match it means that there were no matching logs in the last
|
|
328
|
-
//block so we should fetch the block data
|
|
329
|
-
| Some(_)
|
|
330
|
-
| None =>
|
|
331
|
-
//If there were no logs at all in the current page query then fetch the
|
|
332
|
-
//timestamp of the heighest block accounted for
|
|
333
|
-
HyperFuel.queryBlockData(~serverUrl=endpointUrl, ~blockNumber=heighestBlockQueried, ~logger)
|
|
334
|
-
->Promise.thenResolve(res => {
|
|
335
|
-
switch res {
|
|
336
|
-
| Some(blockData) => blockData
|
|
337
|
-
| None =>
|
|
338
|
-
mkLogAndRaise(
|
|
339
|
-
Not_found,
|
|
340
|
-
~msg=`Failure, blockData for block ${heighestBlockQueried->Int.toString} unexpectedly returned None`,
|
|
341
|
-
)
|
|
342
|
-
}
|
|
343
|
-
})
|
|
344
|
-
->Promise.catch(exn => {
|
|
345
|
-
exn->mkLogAndRaise(
|
|
346
|
-
~msg=`Failed to query blockData for block ${heighestBlockQueried->Int.toString}`,
|
|
347
|
-
)
|
|
348
|
-
})
|
|
349
|
-
}
|
|
350
|
-
|
|
351
301
|
let parsingTimeRef = Hrtime.makeTimer()
|
|
352
302
|
|
|
353
303
|
let parsedQueueItems = pageUnsafe.items->Array.map(item => {
|
|
@@ -463,11 +413,18 @@ let make = ({chain, endpointUrl}: options): t => {
|
|
|
463
413
|
|
|
464
414
|
let parsingTimeElapsed = parsingTimeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
|
|
465
415
|
|
|
466
|
-
|
|
416
|
+
// Fuel never rolls back on reorg, so block hashes here are purely informational
|
|
417
|
+
// for detect-only logging via ReorgDetection.
|
|
418
|
+
let blockHashes = pageUnsafe.items->Array.map(({block}) => {
|
|
419
|
+
ReorgDetection.blockNumber: block.height,
|
|
420
|
+
blockHash: block.id,
|
|
421
|
+
})
|
|
467
422
|
|
|
468
|
-
let
|
|
469
|
-
|
|
470
|
-
|
|
423
|
+
let latestFetchedBlockTimestamp = switch pageUnsafe.items->Belt.Array.get(
|
|
424
|
+
pageUnsafe.items->Belt.Array.length - 1,
|
|
425
|
+
) {
|
|
426
|
+
| Some({block}) if block.height == heighestBlockQueried => block.time
|
|
427
|
+
| _ => 0
|
|
471
428
|
}
|
|
472
429
|
|
|
473
430
|
let totalTimeElapsed = totalTimeRef->Hrtime.timeSince->Hrtime.toSecondsFloat
|
|
@@ -479,12 +436,12 @@ let make = ({chain, endpointUrl}: options): t => {
|
|
|
479
436
|
}
|
|
480
437
|
|
|
481
438
|
{
|
|
482
|
-
latestFetchedBlockTimestamp
|
|
439
|
+
latestFetchedBlockTimestamp,
|
|
483
440
|
parsedQueueItems,
|
|
484
|
-
latestFetchedBlockNumber:
|
|
441
|
+
latestFetchedBlockNumber: heighestBlockQueried,
|
|
485
442
|
stats,
|
|
486
443
|
knownHeight,
|
|
487
|
-
|
|
444
|
+
blockHashes,
|
|
488
445
|
fromBlockQueried: fromBlock,
|
|
489
446
|
}
|
|
490
447
|
}
|
|
@@ -492,7 +449,7 @@ let make = ({chain, endpointUrl}: options): t => {
|
|
|
492
449
|
let getBlockHashes = (~blockNumbers as _, ~logger as _) =>
|
|
493
450
|
JsError.throwWithMessage("HyperFuel does not support getting block hashes")
|
|
494
451
|
|
|
495
|
-
let jsonApiClient =
|
|
452
|
+
let jsonApiClient = EnvioApiClient.make(endpointUrl)
|
|
496
453
|
|
|
497
454
|
{
|
|
498
455
|
name,
|
|
@@ -11,8 +11,8 @@ import * as Prometheus from "../Prometheus.res.mjs";
|
|
|
11
11
|
import * as EventRouter from "./EventRouter.res.mjs";
|
|
12
12
|
import * as ErrorHandling from "../ErrorHandling.res.mjs";
|
|
13
13
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
14
|
+
import * as EnvioApiClient from "./EnvioApiClient.res.mjs";
|
|
14
15
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
15
|
-
import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
|
|
16
16
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
17
17
|
|
|
18
18
|
let EventRoutingFailed = /* @__PURE__ */Primitive_exceptions.create("HyperFuelSource.EventRoutingFailed");
|
|
@@ -182,7 +182,6 @@ function make(param) {
|
|
|
182
182
|
let name = "HyperFuel";
|
|
183
183
|
let getSelectionConfig = memoGetSelectionConfig(chain);
|
|
184
184
|
let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, indexingAddresses, knownHeight, param, selection, retry, logger) => {
|
|
185
|
-
let mkLogAndRaise = (extra, extra$1) => ErrorHandling.mkLogAndRaise(logger, extra, extra$1);
|
|
186
185
|
let totalTimeRef = Hrtime.makeTimer();
|
|
187
186
|
let selectionConfig = getSelectionConfig(selection);
|
|
188
187
|
let recieptsSelection = selectionConfig.getRecieptsSelection(addressesByContractName);
|
|
@@ -238,34 +237,6 @@ function make(param) {
|
|
|
238
237
|
let pageFetchTime = Hrtime.toSecondsFloat(Hrtime.timeSince(startFetchingBatchTimeRef));
|
|
239
238
|
let knownHeight$1 = pageUnsafe.archiveHeight;
|
|
240
239
|
let heighestBlockQueried = pageUnsafe.nextBlock - 1 | 0;
|
|
241
|
-
let match = Belt_Array.get(pageUnsafe.items, pageUnsafe.items.length - 1 | 0);
|
|
242
|
-
let lastBlockQueriedPromise;
|
|
243
|
-
let exit = 0;
|
|
244
|
-
if (match !== undefined) {
|
|
245
|
-
let block = match.block;
|
|
246
|
-
if (block.height === heighestBlockQueried) {
|
|
247
|
-
lastBlockQueriedPromise = Promise.resolve({
|
|
248
|
-
blockHash: block.id,
|
|
249
|
-
blockNumber: block.height,
|
|
250
|
-
blockTimestamp: block.time
|
|
251
|
-
});
|
|
252
|
-
} else {
|
|
253
|
-
exit = 1;
|
|
254
|
-
}
|
|
255
|
-
} else {
|
|
256
|
-
exit = 1;
|
|
257
|
-
}
|
|
258
|
-
if (exit === 1) {
|
|
259
|
-
lastBlockQueriedPromise = Stdlib_Promise.$$catch(HyperFuel.queryBlockData(endpointUrl, heighestBlockQueried, logger).then(res => {
|
|
260
|
-
if (res !== undefined) {
|
|
261
|
-
return res;
|
|
262
|
-
} else {
|
|
263
|
-
return mkLogAndRaise(`Failure, blockData for block ` + heighestBlockQueried.toString() + ` unexpectedly returned None`, {
|
|
264
|
-
RE_EXN_ID: "Not_found"
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
}), exn => mkLogAndRaise(`Failed to query blockData for block ` + heighestBlockQueried.toString(), exn));
|
|
268
|
-
}
|
|
269
240
|
let parsingTimeRef = Hrtime.makeTimer();
|
|
270
241
|
let parsedQueueItems = pageUnsafe.items.map(item => {
|
|
271
242
|
let block = item.block;
|
|
@@ -383,11 +354,21 @@ function make(param) {
|
|
|
383
354
|
};
|
|
384
355
|
});
|
|
385
356
|
let parsingTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(parsingTimeRef));
|
|
386
|
-
let
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
357
|
+
let blockHashes = pageUnsafe.items.map(param => {
|
|
358
|
+
let block = param.block;
|
|
359
|
+
return {
|
|
360
|
+
blockHash: block.id,
|
|
361
|
+
blockNumber: block.height
|
|
362
|
+
};
|
|
363
|
+
});
|
|
364
|
+
let match = Belt_Array.get(pageUnsafe.items, pageUnsafe.items.length - 1 | 0);
|
|
365
|
+
let latestFetchedBlockTimestamp;
|
|
366
|
+
if (match !== undefined) {
|
|
367
|
+
let block = match.block;
|
|
368
|
+
latestFetchedBlockTimestamp = block.height === heighestBlockQueried ? block.time : 0;
|
|
369
|
+
} else {
|
|
370
|
+
latestFetchedBlockTimestamp = 0;
|
|
371
|
+
}
|
|
391
372
|
let totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(totalTimeRef));
|
|
392
373
|
let stats_parsing$unknowntime$unknown$lpars$rpar = parsingTimeElapsed;
|
|
393
374
|
let stats_page$unknownfetch$unknowntime$unknown$lpars$rpar = pageFetchTime;
|
|
@@ -398,16 +379,16 @@ function make(param) {
|
|
|
398
379
|
};
|
|
399
380
|
return {
|
|
400
381
|
knownHeight: knownHeight$1,
|
|
401
|
-
|
|
382
|
+
blockHashes: blockHashes,
|
|
402
383
|
parsedQueueItems: parsedQueueItems,
|
|
403
384
|
fromBlockQueried: fromBlock,
|
|
404
|
-
latestFetchedBlockNumber:
|
|
405
|
-
latestFetchedBlockTimestamp:
|
|
385
|
+
latestFetchedBlockNumber: heighestBlockQueried,
|
|
386
|
+
latestFetchedBlockTimestamp: latestFetchedBlockTimestamp,
|
|
406
387
|
stats: stats
|
|
407
388
|
};
|
|
408
389
|
};
|
|
409
390
|
let getBlockHashes = (param, param$1) => Stdlib_JsError.throwWithMessage("HyperFuel does not support getting block hashes");
|
|
410
|
-
let jsonApiClient =
|
|
391
|
+
let jsonApiClient = EnvioApiClient.make(endpointUrl);
|
|
411
392
|
return {
|
|
412
393
|
name: name,
|
|
413
394
|
sourceFor: "Sync",
|
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
let reraisIfRateLimited = exn =>
|
|
2
|
+
switch exn->JsExn.anyToExnInternal {
|
|
3
|
+
| JsExn(e) =>
|
|
4
|
+
switch e->JsExn.message {
|
|
5
|
+
| Some(msg) if msg->String.startsWith("RATE_LIMITED:") =>
|
|
6
|
+
let resetMs =
|
|
7
|
+
msg
|
|
8
|
+
->String.slice(~start=13, ~end=msg->String.length)
|
|
9
|
+
->Int.fromString
|
|
10
|
+
->Option.getOr(1000)
|
|
11
|
+
throw(Source.RateLimited({resetMs: resetMs}))
|
|
12
|
+
| _ => ()
|
|
13
|
+
}
|
|
14
|
+
| _ => ()
|
|
7
15
|
}
|
|
8
16
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
type hyperSyncPage<'item> = {
|
|
13
|
-
items: array<'item>,
|
|
17
|
+
type logsQueryPage = {
|
|
18
|
+
items: array<HyperSyncClient.EventItems.item>,
|
|
14
19
|
nextBlock: int,
|
|
15
20
|
archiveHeight: int,
|
|
16
21
|
rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
|
|
17
|
-
events: array<HyperSyncClient.ResponseTypes.event>,
|
|
18
22
|
}
|
|
19
23
|
|
|
20
|
-
type logsQueryPageItem = {
|
|
21
|
-
log: Log.t,
|
|
22
|
-
block: HyperSyncClient.ResponseTypes.block,
|
|
23
|
-
transaction: Internal.eventTransaction,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
type logsQueryPage = hyperSyncPage<logsQueryPageItem>
|
|
27
|
-
|
|
28
24
|
type missingParams = {
|
|
29
25
|
queryName: string,
|
|
30
26
|
missingParams: array<string>,
|
|
@@ -74,94 +70,37 @@ module GetLogs = {
|
|
|
74
70
|
fieldSelection,
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
// Rust encodes structured failures as a JSON payload in the napi error's
|
|
74
|
+
// message: `{"kind":"MissingFields","fields":["block.timestamp", ...]}`.
|
|
75
|
+
// JSON.parse + shape check is the recovery protocol — no string-grepping
|
|
76
|
+
// on anyhow's Debug format.
|
|
77
|
+
let extractMissingParams = (exn: exn): option<array<string>> => {
|
|
78
|
+
let message = switch exn {
|
|
79
|
+
| JsExn(jsExn) => jsExn->JsExn.message
|
|
80
|
+
| _ => None
|
|
81
|
+
}
|
|
82
|
+
switch message {
|
|
83
|
+
| None => None
|
|
84
|
+
| Some(msg) =>
|
|
85
|
+
switch msg->JSON.parseOrThrow->JSON.Decode.object {
|
|
86
|
+
| exception _ => None
|
|
87
|
+
| None => None
|
|
88
|
+
| Some(obj) =>
|
|
89
|
+
switch (obj->Dict.get("kind"), obj->Dict.get("fields")) {
|
|
90
|
+
| (Some(String("MissingFields")), Some(Array(fields))) =>
|
|
91
|
+
Some(fields->Array.filterMap(JSON.Decode.string))
|
|
92
|
+
| _ => None
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
//Note this function can throw an error
|
|
97
|
-
let convertEvent = (
|
|
98
|
-
event: HyperSyncClient.ResponseTypes.event,
|
|
99
|
-
~nonOptionalBlockFieldNames,
|
|
100
|
-
~nonOptionalTransactionFieldNames,
|
|
101
|
-
): logsQueryPageItem => {
|
|
102
|
-
let missingParams = []
|
|
103
|
-
missingParams->addMissingParams(Log.fieldNames, event.log, ~prefix="log")
|
|
104
|
-
missingParams->addMissingParams(nonOptionalBlockFieldNames, event.block, ~prefix="block")
|
|
105
|
-
missingParams->addMissingParams(
|
|
106
|
-
nonOptionalTransactionFieldNames,
|
|
107
|
-
event.transaction,
|
|
108
|
-
~prefix="transaction",
|
|
109
|
-
)
|
|
110
|
-
if missingParams->Array.length > 0 {
|
|
111
|
-
throw(Error(UnexpectedMissingParams({missingParams: missingParams})))
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
//Topics can be nullable and still need to be filtered
|
|
115
|
-
let logUnsanitized: Log.t = event.log->(Utils.magic: HyperSyncClient.ResponseTypes.log => Log.t)
|
|
116
|
-
let topics = event.log.topics->Option.getUnsafe->Array.filterMap(Nullable.toOption)
|
|
117
|
-
let address = event.log.address->Option.getUnsafe
|
|
118
|
-
let log = {
|
|
119
|
-
...logUnsanitized,
|
|
120
|
-
topics,
|
|
121
|
-
address,
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
{
|
|
125
|
-
log,
|
|
126
|
-
block: event.block->(
|
|
127
|
-
Utils.magic: option<
|
|
128
|
-
HyperSyncClient.ResponseTypes.block,
|
|
129
|
-
> => HyperSyncClient.ResponseTypes.block
|
|
130
|
-
),
|
|
131
|
-
transaction: event.transaction->(
|
|
132
|
-
Utils.magic: option<HyperSyncClient.ResponseTypes.transaction> => Internal.eventTransaction
|
|
133
|
-
),
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
let convertResponse = (
|
|
138
|
-
res: HyperSyncClient.ResponseTypes.eventResponse,
|
|
139
|
-
~nonOptionalBlockFieldNames,
|
|
140
|
-
~nonOptionalTransactionFieldNames,
|
|
141
|
-
): logsQueryPage => {
|
|
142
|
-
let {nextBlock, archiveHeight, rollbackGuard} = res
|
|
143
|
-
let items =
|
|
144
|
-
res.data->Array.map(item =>
|
|
145
|
-
item->convertEvent(~nonOptionalBlockFieldNames, ~nonOptionalTransactionFieldNames)
|
|
146
|
-
)
|
|
147
|
-
let page: logsQueryPage = {
|
|
148
|
-
items,
|
|
149
|
-
nextBlock,
|
|
150
|
-
archiveHeight: archiveHeight->Option.getOr(0), //Archive Height is only None if height is 0
|
|
151
|
-
events: res.data,
|
|
152
|
-
rollbackGuard,
|
|
153
|
-
}
|
|
154
|
-
page
|
|
155
|
-
}
|
|
156
|
-
|
|
157
98
|
let query = async (
|
|
158
99
|
~client: HyperSyncClient.t,
|
|
159
100
|
~fromBlock,
|
|
160
101
|
~toBlock,
|
|
161
102
|
~logSelections: array<LogSelection.t>,
|
|
162
103
|
~fieldSelection,
|
|
163
|
-
~nonOptionalBlockFieldNames,
|
|
164
|
-
~nonOptionalTransactionFieldNames,
|
|
165
104
|
): logsQueryPage => {
|
|
166
105
|
let addressesWithTopics = logSelections->Array.flatMap(({addresses, topicSelections}) =>
|
|
167
106
|
topicSelections->Array.map(({topic0, topic1, topic2, topic3}) => {
|
|
@@ -182,13 +121,26 @@ module GetLogs = {
|
|
|
182
121
|
~fieldSelection,
|
|
183
122
|
)
|
|
184
123
|
|
|
185
|
-
let res = await client.
|
|
124
|
+
let res = switch await client.getEventItems(~query) {
|
|
125
|
+
| res => res
|
|
126
|
+
| exception exn =>
|
|
127
|
+
reraisIfRateLimited(exn)
|
|
128
|
+
switch extractMissingParams(exn) {
|
|
129
|
+
| Some(missingParams) => throw(Error(UnexpectedMissingParams({missingParams: missingParams})))
|
|
130
|
+
| None => throw(exn)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
186
133
|
if res.nextBlock <= fromBlock {
|
|
187
134
|
// Might happen when /height response was from another instance of HyperSync
|
|
188
135
|
throw(Error(WrongInstance))
|
|
189
136
|
}
|
|
190
137
|
|
|
191
|
-
|
|
138
|
+
{
|
|
139
|
+
items: res.items,
|
|
140
|
+
nextBlock: res.nextBlock,
|
|
141
|
+
archiveHeight: res.archiveHeight->Option.getOr(0), //Archive Height is only None if height is 0
|
|
142
|
+
rollbackGuard: res.rollbackGuard,
|
|
143
|
+
}
|
|
192
144
|
}
|
|
193
145
|
}
|
|
194
146
|
|
|
@@ -258,7 +210,9 @@ module BlockData = {
|
|
|
258
210
|
|
|
259
211
|
Prometheus.SourceRequestCount.increment(~sourceName, ~chainId, ~method="getBlockHashes")
|
|
260
212
|
let maybeSuccessfulRes = switch await client.get(~query=body) {
|
|
261
|
-
| exception
|
|
213
|
+
| exception exn =>
|
|
214
|
+
reraisIfRateLimited(exn)
|
|
215
|
+
None
|
|
262
216
|
| res if res.nextBlock <= fromBlock => None
|
|
263
217
|
| res => Some(res)
|
|
264
218
|
}
|
|
@@ -2,22 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Time from "../Time.res.mjs";
|
|
4
4
|
import * as Utils from "../Utils.res.mjs";
|
|
5
|
+
import * as Source from "./Source.res.mjs";
|
|
5
6
|
import * as Logging from "../Logging.res.mjs";
|
|
6
7
|
import * as Prometheus from "../Prometheus.res.mjs";
|
|
8
|
+
import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
|
|
9
|
+
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
7
10
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
11
|
+
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
8
12
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
9
13
|
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
10
14
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
11
15
|
import * as HyperSyncClient from "./HyperSyncClient.res.mjs";
|
|
12
|
-
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
13
16
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
function reraisIfRateLimited(exn) {
|
|
19
|
+
let e = Primitive_exceptions.internalToException(exn);
|
|
20
|
+
if (e.RE_EXN_ID !== "JsExn") {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
let msg = Stdlib_JsExn.message(e._1);
|
|
24
|
+
if (msg === undefined) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!msg.startsWith("RATE_LIMITED:")) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
let resetMs = Stdlib_Option.getOr(Stdlib_Int.fromString(msg.slice(13, msg.length), undefined), 1000);
|
|
31
|
+
throw {
|
|
32
|
+
RE_EXN_ID: Source.RateLimited,
|
|
33
|
+
resetMs: resetMs,
|
|
34
|
+
Error: new Error()
|
|
35
|
+
};
|
|
36
|
+
}
|
|
21
37
|
|
|
22
38
|
let HyperSyncQueryError = /* @__PURE__ */Primitive_exceptions.create("HyperSync.HyperSyncQueryError");
|
|
23
39
|
|
|
@@ -55,7 +71,28 @@ function makeRequestBody(fromBlock, toBlockInclusive, addressesWithTopics, field
|
|
|
55
71
|
};
|
|
56
72
|
}
|
|
57
73
|
|
|
58
|
-
|
|
74
|
+
function extractMissingParams(exn) {
|
|
75
|
+
let message = exn.RE_EXN_ID === "JsExn" ? Stdlib_JsExn.message(exn._1) : undefined;
|
|
76
|
+
if (message === undefined) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
let obj;
|
|
80
|
+
try {
|
|
81
|
+
obj = Stdlib_JSON.Decode.object(JSON.parse(message));
|
|
82
|
+
} catch (exn$1) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (obj === undefined) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
let match = obj["kind"];
|
|
89
|
+
let match$1 = obj["fields"];
|
|
90
|
+
if (match === "MissingFields" && Array.isArray(match$1)) {
|
|
91
|
+
return Stdlib_Array.filterMap(match$1, Stdlib_JSON.Decode.string);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function query(client, fromBlock, toBlock, logSelections, fieldSelection) {
|
|
59
96
|
let addressesWithTopics = logSelections.flatMap(param => {
|
|
60
97
|
let addresses = param.addresses;
|
|
61
98
|
return param.topicSelections.map(param => {
|
|
@@ -64,65 +101,14 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection,
|
|
|
64
101
|
});
|
|
65
102
|
});
|
|
66
103
|
let query$1 = makeRequestBody(fromBlock, toBlock, addressesWithTopics, fieldSelection);
|
|
67
|
-
let res
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
let items = res.data.map(item => {
|
|
76
|
-
let missingParams = [];
|
|
77
|
-
let returnedObj = item.log;
|
|
78
|
-
if (Utils.$$Array.notEmpty(fieldNames)) {
|
|
79
|
-
if (returnedObj) {
|
|
80
|
-
for (let idx = 0, idx_finish = fieldNames.length; idx < idx_finish; ++idx) {
|
|
81
|
-
let fieldName = fieldNames[idx];
|
|
82
|
-
let match = returnedObj[fieldName];
|
|
83
|
-
if (match !== undefined) {
|
|
84
|
-
|
|
85
|
-
} else {
|
|
86
|
-
missingParams.push("log." + fieldName);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
} else {
|
|
90
|
-
missingParams.push("log");
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
let returnedObj$1 = item.block;
|
|
94
|
-
if (Utils.$$Array.notEmpty(nonOptionalBlockFieldNames)) {
|
|
95
|
-
if (returnedObj$1) {
|
|
96
|
-
for (let idx$1 = 0, idx_finish$1 = nonOptionalBlockFieldNames.length; idx$1 < idx_finish$1; ++idx$1) {
|
|
97
|
-
let fieldName$1 = nonOptionalBlockFieldNames[idx$1];
|
|
98
|
-
let match$1 = returnedObj$1[fieldName$1];
|
|
99
|
-
if (match$1 !== undefined) {
|
|
100
|
-
|
|
101
|
-
} else {
|
|
102
|
-
missingParams.push("block." + fieldName$1);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
missingParams.push("block");
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
let returnedObj$2 = item.transaction;
|
|
110
|
-
if (Utils.$$Array.notEmpty(nonOptionalTransactionFieldNames)) {
|
|
111
|
-
if (returnedObj$2) {
|
|
112
|
-
for (let idx$2 = 0, idx_finish$2 = nonOptionalTransactionFieldNames.length; idx$2 < idx_finish$2; ++idx$2) {
|
|
113
|
-
let fieldName$2 = nonOptionalTransactionFieldNames[idx$2];
|
|
114
|
-
let match$2 = returnedObj$2[fieldName$2];
|
|
115
|
-
if (match$2 !== undefined) {
|
|
116
|
-
|
|
117
|
-
} else {
|
|
118
|
-
missingParams.push("transaction." + fieldName$2);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
} else {
|
|
122
|
-
missingParams.push("transaction");
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (missingParams.length !== 0) {
|
|
104
|
+
let res;
|
|
105
|
+
try {
|
|
106
|
+
res = await client.getEventItems(query$1);
|
|
107
|
+
} catch (raw_exn) {
|
|
108
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
109
|
+
reraisIfRateLimited(exn);
|
|
110
|
+
let missingParams = extractMissingParams(exn);
|
|
111
|
+
if (missingParams !== undefined) {
|
|
126
112
|
throw {
|
|
127
113
|
RE_EXN_ID: $$Error,
|
|
128
114
|
_1: {
|
|
@@ -132,35 +118,20 @@ async function query(client, fromBlock, toBlock, logSelections, fieldSelection,
|
|
|
132
118
|
Error: new Error()
|
|
133
119
|
};
|
|
134
120
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
});
|
|
143
|
-
let address = item.log.address;
|
|
144
|
-
let log_data = logUnsanitized.data;
|
|
145
|
-
let log_logIndex = logUnsanitized.logIndex;
|
|
146
|
-
let log = {
|
|
147
|
-
address: address,
|
|
148
|
-
data: log_data,
|
|
149
|
-
topics: topics,
|
|
150
|
-
logIndex: log_logIndex
|
|
151
|
-
};
|
|
152
|
-
return {
|
|
153
|
-
log: log,
|
|
154
|
-
block: item.block,
|
|
155
|
-
transaction: item.transaction
|
|
121
|
+
throw exn;
|
|
122
|
+
}
|
|
123
|
+
if (res.nextBlock <= fromBlock) {
|
|
124
|
+
throw {
|
|
125
|
+
RE_EXN_ID: $$Error,
|
|
126
|
+
_1: "WrongInstance",
|
|
127
|
+
Error: new Error()
|
|
156
128
|
};
|
|
157
|
-
}
|
|
129
|
+
}
|
|
158
130
|
return {
|
|
159
|
-
items: items,
|
|
131
|
+
items: res.items,
|
|
160
132
|
nextBlock: res.nextBlock,
|
|
161
133
|
archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0),
|
|
162
|
-
rollbackGuard: res.rollbackGuard
|
|
163
|
-
events: res.data
|
|
134
|
+
rollbackGuard: res.rollbackGuard
|
|
164
135
|
};
|
|
165
136
|
}
|
|
166
137
|
|
|
@@ -230,7 +201,9 @@ async function queryBlockData(client, fromBlock, toBlock, sourceName, chainId, l
|
|
|
230
201
|
try {
|
|
231
202
|
res = await client.get(body);
|
|
232
203
|
exit = 1;
|
|
233
|
-
} catch (
|
|
204
|
+
} catch (raw_exn) {
|
|
205
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
206
|
+
reraisIfRateLimited(exn);
|
|
234
207
|
maybeSuccessfulRes = undefined;
|
|
235
208
|
}
|
|
236
209
|
if (exit === 1) {
|
|
@@ -289,15 +262,13 @@ function queryBlockData$1(client, blockNumber, sourceName, chainId, logger) {
|
|
|
289
262
|
return queryBlockData(client, blockNumber, blockNumber, sourceName, chainId, logger).then(res => Stdlib_Result.map(res, res => res[0]));
|
|
290
263
|
}
|
|
291
264
|
|
|
292
|
-
let Log = {};
|
|
293
|
-
|
|
294
265
|
let GetLogs = {
|
|
295
266
|
$$Error: $$Error,
|
|
267
|
+
extractMissingParams: extractMissingParams,
|
|
296
268
|
query: query
|
|
297
269
|
};
|
|
298
270
|
|
|
299
271
|
export {
|
|
300
|
-
Log,
|
|
301
272
|
queryErrorToMsq,
|
|
302
273
|
GetLogs,
|
|
303
274
|
queryBlockData$1 as queryBlockData,
|
|
@@ -1,28 +1,10 @@
|
|
|
1
|
-
type
|
|
2
|
-
items: array<
|
|
1
|
+
type logsQueryPage = {
|
|
2
|
+
items: array<HyperSyncClient.EventItems.item>,
|
|
3
3
|
nextBlock: int,
|
|
4
4
|
archiveHeight: int,
|
|
5
5
|
rollbackGuard: option<HyperSyncClient.ResponseTypes.rollbackGuard>,
|
|
6
|
-
events: array<HyperSyncClient.ResponseTypes.event>,
|
|
7
6
|
}
|
|
8
7
|
|
|
9
|
-
module Log: {
|
|
10
|
-
type t = {
|
|
11
|
-
address: Address.t,
|
|
12
|
-
data: string,
|
|
13
|
-
topics: array<EvmTypes.Hex.t>,
|
|
14
|
-
logIndex: int,
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
type logsQueryPageItem = {
|
|
19
|
-
log: Log.t,
|
|
20
|
-
block: HyperSyncClient.ResponseTypes.block,
|
|
21
|
-
transaction: Internal.eventTransaction,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
type logsQueryPage = hyperSyncPage<logsQueryPageItem>
|
|
25
|
-
|
|
26
8
|
type missingParams = {
|
|
27
9
|
queryName: string,
|
|
28
10
|
missingParams: array<string>,
|
|
@@ -41,14 +23,14 @@ module GetLogs: {
|
|
|
41
23
|
|
|
42
24
|
exception Error(error)
|
|
43
25
|
|
|
26
|
+
let extractMissingParams: exn => option<array<string>>
|
|
27
|
+
|
|
44
28
|
let query: (
|
|
45
29
|
~client: HyperSyncClient.t,
|
|
46
30
|
~fromBlock: int,
|
|
47
31
|
~toBlock: option<int>,
|
|
48
32
|
~logSelections: array<LogSelection.t>,
|
|
49
33
|
~fieldSelection: HyperSyncClient.QueryTypes.fieldSelection,
|
|
50
|
-
~nonOptionalBlockFieldNames: array<string>,
|
|
51
|
-
~nonOptionalTransactionFieldNames: array<string>,
|
|
52
34
|
) => promise<logsQueryPage>
|
|
53
35
|
}
|
|
54
36
|
|