envio 3.3.0-alpha.7 → 3.3.0-alpha.8
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/index.d.ts +23 -5
- package/package.json +6 -6
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/ChainFetching.res +21 -10
- package/src/ChainFetching.res.mjs +11 -10
- package/src/ChainState.res +328 -165
- package/src/ChainState.res.mjs +205 -100
- package/src/ChainState.resi +16 -7
- package/src/Config.res +11 -27
- package/src/Config.res.mjs +8 -7
- package/src/Core.res +7 -0
- package/src/CrossChainState.res +53 -80
- package/src/CrossChainState.res.mjs +43 -59
- package/src/CrossChainState.resi +1 -1
- package/src/Ecosystem.res +3 -3
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Envio.res +14 -9
- package/src/EventConfigBuilder.res +105 -56
- package/src/EventConfigBuilder.res.mjs +69 -33
- package/src/EventProcessing.res +19 -15
- package/src/EventProcessing.res.mjs +13 -12
- package/src/FetchState.res +375 -171
- package/src/FetchState.res.mjs +249 -251
- package/src/HandlerLoader.res +7 -112
- package/src/HandlerLoader.res.mjs +1 -87
- package/src/HandlerRegister.res +209 -6
- package/src/HandlerRegister.res.mjs +90 -5
- package/src/HandlerRegister.resi +13 -2
- package/src/IndexerState.res +6 -3
- package/src/IndexerState.res.mjs +3 -3
- package/src/IndexerState.resi +1 -1
- package/src/IndexingAddresses.res +10 -7
- package/src/IndexingAddresses.res.mjs +8 -7
- package/src/IndexingAddresses.resi +3 -1
- package/src/Internal.res +82 -36
- package/src/Internal.res.mjs +11 -1
- package/src/Main.res +22 -23
- package/src/Main.res.mjs +15 -17
- package/src/Metrics.res +43 -2
- package/src/Metrics.res.mjs +39 -3
- package/src/Prometheus.res +0 -35
- package/src/Prometheus.res.mjs +33 -68
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/SimulateItems.res +20 -7
- package/src/SimulateItems.res.mjs +7 -11
- package/src/TestIndexer.res +1 -1
- package/src/TestIndexer.res.mjs +1 -1
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +19 -12
- package/src/sources/EventRouter.res.mjs +7 -5
- package/src/sources/Evm.res +54 -4
- package/src/sources/Evm.res.mjs +43 -4
- package/src/sources/EvmChain.res +14 -18
- package/src/sources/EvmChain.res.mjs +12 -13
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +5 -2
- package/src/sources/Fuel.res.mjs +4 -3
- package/src/sources/HyperFuelSource.res +31 -40
- package/src/sources/HyperFuelSource.res.mjs +52 -44
- package/src/sources/HyperSync.res +31 -9
- package/src/sources/HyperSync.res.mjs +47 -31
- package/src/sources/HyperSync.resi +10 -3
- package/src/sources/HyperSyncClient.res +15 -4
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +37 -58
- package/src/sources/HyperSyncSource.res.mjs +42 -42
- package/src/sources/RpcSource.res +91 -82
- package/src/sources/RpcSource.res.mjs +76 -45
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +5 -3
- package/src/sources/SimulateSource.res.mjs +12 -4
- package/src/sources/Source.res +19 -5
- package/src/sources/SourceManager.res +62 -6
- package/src/sources/SourceManager.res.mjs +55 -8
- package/src/sources/SourceManager.resi +10 -0
- package/src/sources/Svm.res +14 -10
- package/src/sources/Svm.res.mjs +23 -6
- package/src/sources/SvmHyperSyncClient.res +5 -6
- package/src/sources/SvmHyperSyncSource.res +82 -41
- package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
- package/src/sources/TransactionStore.res +6 -107
- package/src/sources/TransactionStore.res.mjs +5 -86
- package/svm.schema.json +19 -0
|
@@ -48,18 +48,16 @@ let getKnownRawBlockWithBackoff = async (
|
|
|
48
48
|
~chain,
|
|
49
49
|
~blockNumber,
|
|
50
50
|
~backoffMsOnFailure,
|
|
51
|
+
~recordRequest: (~method: string, ~seconds: float) => unit,
|
|
51
52
|
) => {
|
|
52
53
|
let currentBackoff = ref(backoffMsOnFailure)
|
|
53
54
|
let result = ref(None)
|
|
54
55
|
|
|
55
56
|
while result.contents->Option.isNone {
|
|
56
|
-
|
|
57
|
-
~sourceName,
|
|
58
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
59
|
-
~method="eth_getBlockByNumber",
|
|
60
|
-
)
|
|
57
|
+
let timerRef = Performance.now()
|
|
61
58
|
switch await getKnownRawBlock(~client, ~blockNumber) {
|
|
62
59
|
| exception err =>
|
|
60
|
+
recordRequest(~method="eth_getBlockByNumber", ~seconds=timerRef->Performance.secondsSince)
|
|
63
61
|
Logging.warn({
|
|
64
62
|
"err": err->Utils.prettifyExn,
|
|
65
63
|
"msg": `Issue while running fetching batch of events from the RPC. Will wait ${currentBackoff.contents->Int.toString}ms and try again.`,
|
|
@@ -69,7 +67,9 @@ let getKnownRawBlockWithBackoff = async (
|
|
|
69
67
|
})
|
|
70
68
|
await Time.resolvePromiseAfterDelay(~delayMilliseconds=currentBackoff.contents)
|
|
71
69
|
currentBackoff := currentBackoff.contents * 2
|
|
72
|
-
| json =>
|
|
70
|
+
| json =>
|
|
71
|
+
recordRequest(~method="eth_getBlockByNumber", ~seconds=timerRef->Performance.secondsSince)
|
|
72
|
+
result := Some(json)
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
result.contents->Option.getOrThrow
|
|
@@ -300,8 +300,7 @@ let getNextPage = (
|
|
|
300
300
|
~rpcClient: EvmRpcClient.t,
|
|
301
301
|
~mutSuggestedBlockIntervals,
|
|
302
302
|
~partitionId,
|
|
303
|
-
~
|
|
304
|
-
~chainId,
|
|
303
|
+
~recordRequest: (~method: string, ~seconds: float) => unit,
|
|
305
304
|
): promise<eventBatchQuery> => {
|
|
306
305
|
//If the query hangs for longer than this, reject this promise to reduce the block interval
|
|
307
306
|
let queryTimoutPromise =
|
|
@@ -314,7 +313,7 @@ let getNextPage = (
|
|
|
314
313
|
let latestFetchedBlockPromise = loadBlock(toBlock)
|
|
315
314
|
|
|
316
315
|
let queryLogs = ({addresses, topicQuery}: logSelection) => {
|
|
317
|
-
|
|
316
|
+
let timerRef = Performance.now()
|
|
318
317
|
rpcClient.getLogs({
|
|
319
318
|
fromBlock,
|
|
320
319
|
toBlock,
|
|
@@ -326,6 +325,9 @@ let getNextPage = (
|
|
|
326
325
|
| Multiple(topics) => Nullable.make(topics)
|
|
327
326
|
}
|
|
328
327
|
),
|
|
328
|
+
})->Promise.thenResolve(items => {
|
|
329
|
+
recordRequest(~method="eth_getLogs", ~seconds=timerRef->Performance.secondsSince)
|
|
330
|
+
items
|
|
329
331
|
})
|
|
330
332
|
}
|
|
331
333
|
|
|
@@ -411,12 +413,12 @@ type selectionConfig = {
|
|
|
411
413
|
}
|
|
412
414
|
|
|
413
415
|
let getSelectionConfig = (selection: FetchState.selection, ~chain) => {
|
|
414
|
-
let
|
|
415
|
-
selection.
|
|
416
|
-
Utils.magic: array<Internal.
|
|
416
|
+
let evmOnEventRegistrations =
|
|
417
|
+
selection.onEventRegistrations->(
|
|
418
|
+
Utils.magic: array<Internal.onEventRegistration> => array<Internal.evmOnEventRegistration>
|
|
417
419
|
)
|
|
418
420
|
|
|
419
|
-
if
|
|
421
|
+
if evmOnEventRegistrations->Utils.Array.isEmpty {
|
|
420
422
|
throw(
|
|
421
423
|
Source.GetItemsError(
|
|
422
424
|
UnsupportedSelection({
|
|
@@ -439,12 +441,9 @@ let getSelectionConfig = (selection: FetchState.selection, ~chain) => {
|
|
|
439
441
|
let dynamicWildcardByContract = Dict.make()
|
|
440
442
|
let contractNames = Utils.Set.make()
|
|
441
443
|
|
|
442
|
-
|
|
443
|
-
contractName
|
|
444
|
-
isWildcard,
|
|
445
|
-
dependsOnAddresses,
|
|
446
|
-
getEventFiltersOrThrow,
|
|
447
|
-
}) => {
|
|
444
|
+
evmOnEventRegistrations->Array.forEach(reg => {
|
|
445
|
+
let contractName = reg.eventConfig.contractName
|
|
446
|
+
let {isWildcard, dependsOnAddresses, getEventFiltersOrThrow} = reg
|
|
448
447
|
let eventFilters = getEventFiltersOrThrow(chain)
|
|
449
448
|
if dependsOnAddresses {
|
|
450
449
|
contractNames->Utils.Set.add(contractName)->ignore
|
|
@@ -674,11 +673,9 @@ let makeThrowingGetEventBlock = (
|
|
|
674
673
|
}
|
|
675
674
|
}
|
|
676
675
|
|
|
677
|
-
// `number
|
|
678
|
-
//
|
|
676
|
+
// `number` is always part of the selected block fields, so it can be read
|
|
677
|
+
// from the assembled block for the item's own `blockNumber`.
|
|
679
678
|
@get external getBlockNumber: Internal.eventBlock => int = "number"
|
|
680
|
-
@get external getBlockTimestamp: Internal.eventBlock => int = "timestamp"
|
|
681
|
-
@get external getBlockHash: Internal.eventBlock => string = "hash"
|
|
682
679
|
|
|
683
680
|
// Field source classification for RPC calls
|
|
684
681
|
type fieldSource = TransactionOnly | ReceiptOnly | Both
|
|
@@ -994,7 +991,7 @@ type options = {
|
|
|
994
991
|
syncConfig: Config.sourceSync,
|
|
995
992
|
url: string,
|
|
996
993
|
chain: ChainMap.Chain.t,
|
|
997
|
-
eventRouter: EventRouter.t<Internal.
|
|
994
|
+
eventRouter: EventRouter.t<Internal.evmOnEventRegistration>,
|
|
998
995
|
allEventParams: array<HyperSyncClient.Decoder.eventParamsInput>,
|
|
999
996
|
lowercaseAddresses: bool,
|
|
1000
997
|
ws?: string,
|
|
@@ -1040,15 +1037,37 @@ let make = (
|
|
|
1040
1037
|
~headers?,
|
|
1041
1038
|
)
|
|
1042
1039
|
|
|
1040
|
+
// Requests are made from shared, memoized loaders, so they can't be
|
|
1041
|
+
// attributed to a single getItemsOrThrow/getHeightOrThrow/getBlockHashes
|
|
1042
|
+
// call at its call site. Every actual request (cache/dedup hits never reach
|
|
1043
|
+
// recordRequest) pushes here; each method drains whatever is pending when it
|
|
1044
|
+
// returns. Since a push always lands in exactly one drain, per-source totals
|
|
1045
|
+
// stay exact even with concurrent in-flight calls — which call happens to
|
|
1046
|
+
// drain a given entry doesn't matter, since SourceManager aggregates by
|
|
1047
|
+
// (source, method) regardless of which call returned it.
|
|
1048
|
+
let pendingRequestStats: array<Source.requestStat> = []
|
|
1049
|
+
let recordRequest = (~method, ~seconds) => {
|
|
1050
|
+
pendingRequestStats->Array.push({Source.method, seconds})->ignore
|
|
1051
|
+
}
|
|
1052
|
+
let drainRequestStats = () => {
|
|
1053
|
+
let stats = pendingRequestStats->Utils.Array.copy
|
|
1054
|
+
pendingRequestStats->Utils.Array.clearInPlace
|
|
1055
|
+
stats
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1043
1058
|
let makeTransactionLoader = () =>
|
|
1044
1059
|
LazyLoader.make(
|
|
1045
1060
|
~loaderFn=transactionHash => {
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1061
|
+
let timerRef = Performance.now()
|
|
1062
|
+
Rpc.GetTransactionByHash.rawRoute
|
|
1063
|
+
->Rest.fetch(transactionHash, ~client)
|
|
1064
|
+
->Promise.thenResolve(res => {
|
|
1065
|
+
recordRequest(
|
|
1066
|
+
~method="eth_getTransactionByHash",
|
|
1067
|
+
~seconds=timerRef->Performance.secondsSince,
|
|
1068
|
+
)
|
|
1069
|
+
res
|
|
1070
|
+
})
|
|
1052
1071
|
},
|
|
1053
1072
|
~onError=(am, ~exn) => {
|
|
1054
1073
|
Logging.error({
|
|
@@ -1076,6 +1095,7 @@ let make = (
|
|
|
1076
1095
|
~chain,
|
|
1077
1096
|
~backoffMsOnFailure=1000,
|
|
1078
1097
|
~blockNumber,
|
|
1098
|
+
~recordRequest,
|
|
1079
1099
|
)
|
|
1080
1100
|
},
|
|
1081
1101
|
~onError=(am, ~exn) => {
|
|
@@ -1098,12 +1118,16 @@ let make = (
|
|
|
1098
1118
|
let makeReceiptLoader = () =>
|
|
1099
1119
|
LazyLoader.make(
|
|
1100
1120
|
~loaderFn=transactionHash => {
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1121
|
+
let timerRef = Performance.now()
|
|
1122
|
+
Rpc.GetTransactionReceipt.rawRoute
|
|
1123
|
+
->Rest.fetch(transactionHash, ~client)
|
|
1124
|
+
->Promise.thenResolve(res => {
|
|
1125
|
+
recordRequest(
|
|
1126
|
+
~method="eth_getTransactionReceipt",
|
|
1127
|
+
~seconds=timerRef->Performance.secondsSince,
|
|
1128
|
+
)
|
|
1129
|
+
res
|
|
1130
|
+
})
|
|
1107
1131
|
},
|
|
1108
1132
|
~onError=(am, ~exn) => {
|
|
1109
1133
|
Logging.error({
|
|
@@ -1211,8 +1235,7 @@ let make = (
|
|
|
1211
1235
|
~rpcClient,
|
|
1212
1236
|
~mutSuggestedBlockIntervals,
|
|
1213
1237
|
~partitionId,
|
|
1214
|
-
~
|
|
1215
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
1238
|
+
~recordRequest,
|
|
1216
1239
|
)
|
|
1217
1240
|
|
|
1218
1241
|
let executedBlockInterval = suggestedToBlock - fromBlock + 1
|
|
@@ -1246,7 +1269,11 @@ let make = (
|
|
|
1246
1269
|
~contractAddress=routedAddress,
|
|
1247
1270
|
) {
|
|
1248
1271
|
| None => None
|
|
1249
|
-
| Some(
|
|
1272
|
+
| Some(onEventRegistration) =>
|
|
1273
|
+
let eventConfig =
|
|
1274
|
+
onEventRegistration.eventConfig->(
|
|
1275
|
+
Utils.magic: Internal.eventConfig => Internal.evmEventConfig
|
|
1276
|
+
)
|
|
1250
1277
|
switch maybeDecodedEvent
|
|
1251
1278
|
->Nullable.toOption
|
|
1252
1279
|
->Option.flatMap(Dict.get(_, eventConfig.contractName)) {
|
|
@@ -1293,10 +1320,8 @@ let make = (
|
|
|
1293
1320
|
}
|
|
1294
1321
|
|
|
1295
1322
|
Internal.Event({
|
|
1296
|
-
|
|
1297
|
-
timestamp: block->getBlockTimestamp,
|
|
1323
|
+
onEventRegistration: (onEventRegistration :> Internal.onEventRegistration),
|
|
1298
1324
|
blockNumber: block->getBlockNumber,
|
|
1299
|
-
blockHash: block->getBlockHash,
|
|
1300
1325
|
chain,
|
|
1301
1326
|
logIndex: log.logIndex,
|
|
1302
1327
|
transactionIndex: log.transactionIndex,
|
|
@@ -1350,14 +1375,16 @@ let make = (
|
|
|
1350
1375
|
latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
|
|
1351
1376
|
latestFetchedBlockNumber: latestFetchedBlockInfo.number,
|
|
1352
1377
|
parsedQueueItems,
|
|
1353
|
-
// RPC keeps the transaction inline on the payload; no store
|
|
1378
|
+
// RPC keeps the transaction and block inline on the payload; no store pages.
|
|
1354
1379
|
transactionStore: None,
|
|
1380
|
+
blockStore: None,
|
|
1355
1381
|
stats: {
|
|
1356
1382
|
totalTimeElapsed: totalTimeElapsed,
|
|
1357
1383
|
},
|
|
1358
1384
|
knownHeight,
|
|
1359
1385
|
blockHashes,
|
|
1360
1386
|
fromBlockQueried: fromBlock,
|
|
1387
|
+
requestStats: drainRequestStats(),
|
|
1361
1388
|
}
|
|
1362
1389
|
}
|
|
1363
1390
|
|
|
@@ -1374,21 +1401,25 @@ let make = (
|
|
|
1374
1401
|
->Array.map(blockNum => blockLoader.contents->LazyLoader.get(blockNum))
|
|
1375
1402
|
->Promise.all
|
|
1376
1403
|
->Promise.thenResolve(rawBlocks => {
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1404
|
+
let result =
|
|
1405
|
+
rawBlocks
|
|
1406
|
+
->Array.map(json => {
|
|
1407
|
+
let b = parseBlockInfo(json)
|
|
1408
|
+
|
|
1409
|
+
(
|
|
1410
|
+
{
|
|
1411
|
+
blockNumber: b.number,
|
|
1412
|
+
blockHash: b.hash,
|
|
1413
|
+
blockTimestamp: b.timestamp,
|
|
1414
|
+
}: ReorgDetection.blockDataWithTimestamp
|
|
1415
|
+
)
|
|
1416
|
+
})
|
|
1417
|
+
->Ok
|
|
1418
|
+
{Source.result, requestStats: drainRequestStats()}
|
|
1390
1419
|
})
|
|
1391
|
-
->Promise.catch(exn =>
|
|
1420
|
+
->Promise.catch(exn =>
|
|
1421
|
+
{Source.result: Error(exn), requestStats: drainRequestStats()}->Promise.resolve
|
|
1422
|
+
)
|
|
1392
1423
|
}
|
|
1393
1424
|
|
|
1394
1425
|
let createHeightSubscription =
|
|
@@ -1410,33 +1441,11 @@ let make = (
|
|
|
1410
1441
|
await rpcClient.getHeight()
|
|
1411
1442
|
} catch {
|
|
1412
1443
|
| exn =>
|
|
1413
|
-
|
|
1414
|
-
Prometheus.SourceRequestCount.increment(
|
|
1415
|
-
~sourceName=name,
|
|
1416
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
1417
|
-
~method="eth_blockNumber",
|
|
1418
|
-
)
|
|
1419
|
-
Prometheus.SourceRequestCount.addSeconds(
|
|
1420
|
-
~sourceName=name,
|
|
1421
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
1422
|
-
~method="eth_blockNumber",
|
|
1423
|
-
~seconds,
|
|
1424
|
-
)
|
|
1444
|
+
recordRequest(~method="eth_blockNumber", ~seconds=timerRef->Performance.secondsSince)
|
|
1425
1445
|
exn->throw
|
|
1426
1446
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
~sourceName=name,
|
|
1430
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
1431
|
-
~method="eth_blockNumber",
|
|
1432
|
-
)
|
|
1433
|
-
Prometheus.SourceRequestCount.addSeconds(
|
|
1434
|
-
~sourceName=name,
|
|
1435
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
1436
|
-
~method="eth_blockNumber",
|
|
1437
|
-
~seconds,
|
|
1438
|
-
)
|
|
1439
|
-
height
|
|
1447
|
+
recordRequest(~method="eth_blockNumber", ~seconds=timerRef->Performance.secondsSince)
|
|
1448
|
+
{height, requestStats: drainRequestStats()}
|
|
1440
1449
|
},
|
|
1441
1450
|
getItemsOrThrow,
|
|
1442
1451
|
?createHeightSubscription,
|
|
@@ -9,7 +9,6 @@ import * as Address from "../Address.res.mjs";
|
|
|
9
9
|
import * as Logging from "../Logging.res.mjs";
|
|
10
10
|
import * as Internal from "../Internal.res.mjs";
|
|
11
11
|
import * as LazyLoader from "../LazyLoader.res.mjs";
|
|
12
|
-
import * as Prometheus from "../Prometheus.res.mjs";
|
|
13
12
|
import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
|
|
14
13
|
import * as EventRouter from "./EventRouter.res.mjs";
|
|
15
14
|
import * as Performance from "../bindings/Performance.res.mjs";
|
|
@@ -47,11 +46,11 @@ function parseBlockInfo(json) {
|
|
|
47
46
|
};
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumber, backoffMsOnFailure) {
|
|
49
|
+
async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumber, backoffMsOnFailure, recordRequest) {
|
|
51
50
|
let currentBackoff = backoffMsOnFailure;
|
|
52
51
|
let result;
|
|
53
52
|
while (Stdlib_Option.isNone(result)) {
|
|
54
|
-
|
|
53
|
+
let timerRef = Performance.now();
|
|
55
54
|
let exit = 0;
|
|
56
55
|
let json;
|
|
57
56
|
try {
|
|
@@ -59,6 +58,7 @@ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumbe
|
|
|
59
58
|
exit = 1;
|
|
60
59
|
} catch (raw_err) {
|
|
61
60
|
let err = Primitive_exceptions.internalToException(raw_err);
|
|
61
|
+
recordRequest("eth_getBlockByNumber", Performance.secondsSince(timerRef));
|
|
62
62
|
Logging.warn({
|
|
63
63
|
err: Utils.prettifyExn(err),
|
|
64
64
|
msg: `Issue while running fetching batch of events from the RPC. Will wait ` + currentBackoff.toString() + `ms and try again.`,
|
|
@@ -70,6 +70,7 @@ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumbe
|
|
|
70
70
|
currentBackoff = (currentBackoff << 1);
|
|
71
71
|
}
|
|
72
72
|
if (exit === 1) {
|
|
73
|
+
recordRequest("eth_getBlockByNumber", Performance.secondsSince(timerRef));
|
|
73
74
|
result = json;
|
|
74
75
|
}
|
|
75
76
|
};
|
|
@@ -265,14 +266,14 @@ function mergeAndDedupItems(itemsPerSelection) {
|
|
|
265
266
|
return merged;
|
|
266
267
|
}
|
|
267
268
|
|
|
268
|
-
function getNextPage(fromBlock, toBlock, logSelections, loadBlock, sc, rpcClient, mutSuggestedBlockIntervals, partitionId,
|
|
269
|
+
function getNextPage(fromBlock, toBlock, logSelections, loadBlock, sc, rpcClient, mutSuggestedBlockIntervals, partitionId, recordRequest) {
|
|
269
270
|
let queryTimoutPromise = Time.resolvePromiseAfterDelay(sc.queryTimeoutMillis).then(() => Promise.reject({
|
|
270
271
|
RE_EXN_ID: QueryTimout,
|
|
271
272
|
_1: `Query took longer than ` + (sc.queryTimeoutMillis / 1000 | 0).toString() + ` seconds`
|
|
272
273
|
}));
|
|
273
274
|
let latestFetchedBlockPromise = loadBlock(toBlock);
|
|
274
275
|
let queryLogs = param => {
|
|
275
|
-
|
|
276
|
+
let timerRef = Performance.now();
|
|
276
277
|
return rpcClient.getLogs({
|
|
277
278
|
fromBlock: fromBlock,
|
|
278
279
|
toBlock: toBlock,
|
|
@@ -286,6 +287,9 @@ function getNextPage(fromBlock, toBlock, logSelections, loadBlock, sc, rpcClient
|
|
|
286
287
|
return filter;
|
|
287
288
|
}
|
|
288
289
|
})
|
|
290
|
+
}).then(items => {
|
|
291
|
+
recordRequest("eth_getLogs", Performance.secondsSince(timerRef));
|
|
292
|
+
return items;
|
|
289
293
|
});
|
|
290
294
|
};
|
|
291
295
|
let len = logSelections.length;
|
|
@@ -353,8 +357,8 @@ function getNextPage(fromBlock, toBlock, logSelections, loadBlock, sc, rpcClient
|
|
|
353
357
|
}
|
|
354
358
|
|
|
355
359
|
function getSelectionConfig(selection, chain) {
|
|
356
|
-
let
|
|
357
|
-
if (Utils.$$Array.isEmpty(
|
|
360
|
+
let evmOnEventRegistrations = selection.onEventRegistrations;
|
|
361
|
+
if (Utils.$$Array.isEmpty(evmOnEventRegistrations)) {
|
|
358
362
|
throw {
|
|
359
363
|
RE_EXN_ID: Source.GetItemsError,
|
|
360
364
|
_1: {
|
|
@@ -369,15 +373,15 @@ function getSelectionConfig(selection, chain) {
|
|
|
369
373
|
let dynamicByContract = {};
|
|
370
374
|
let dynamicWildcardByContract = {};
|
|
371
375
|
let contractNames = new Set();
|
|
372
|
-
|
|
373
|
-
let contractName =
|
|
374
|
-
let eventFilters =
|
|
375
|
-
if (
|
|
376
|
+
evmOnEventRegistrations.forEach(reg => {
|
|
377
|
+
let contractName = reg.eventConfig.contractName;
|
|
378
|
+
let eventFilters = reg.getEventFiltersOrThrow(chain);
|
|
379
|
+
if (reg.dependsOnAddresses) {
|
|
376
380
|
contractNames.add(contractName);
|
|
377
381
|
if (eventFilters.TAG === "Static") {
|
|
378
382
|
return Utils.Dict.pushMany(staticByContract, contractName, eventFilters._0);
|
|
379
383
|
} else {
|
|
380
|
-
return Utils.Dict.push(
|
|
384
|
+
return Utils.Dict.push(reg.isWildcard ? dynamicWildcardByContract : dynamicByContract, contractName, eventFilters._0);
|
|
381
385
|
}
|
|
382
386
|
}
|
|
383
387
|
let tmp;
|
|
@@ -973,9 +977,24 @@ function make(param) {
|
|
|
973
977
|
let mutSuggestedBlockIntervals = {};
|
|
974
978
|
let client = Rpc.makeClient(url, headers);
|
|
975
979
|
let rpcClient = EvmRpcClient.make(url, !lowercaseAddresses, undefined, headers, param.allEventParams);
|
|
980
|
+
let pendingRequestStats = [];
|
|
981
|
+
let recordRequest = (method, seconds) => {
|
|
982
|
+
pendingRequestStats.push({
|
|
983
|
+
method: method,
|
|
984
|
+
seconds: seconds
|
|
985
|
+
});
|
|
986
|
+
};
|
|
987
|
+
let drainRequestStats = () => {
|
|
988
|
+
let stats = pendingRequestStats.slice();
|
|
989
|
+
Utils.$$Array.clearInPlace(pendingRequestStats);
|
|
990
|
+
return stats;
|
|
991
|
+
};
|
|
976
992
|
let makeTransactionLoader = () => LazyLoader.make(transactionHash => {
|
|
977
|
-
|
|
978
|
-
return Rest.fetch(Rpc.GetTransactionByHash.rawRoute, transactionHash, client)
|
|
993
|
+
let timerRef = Performance.now();
|
|
994
|
+
return Rest.fetch(Rpc.GetTransactionByHash.rawRoute, transactionHash, client).then(res => {
|
|
995
|
+
recordRequest("eth_getTransactionByHash", Performance.secondsSince(timerRef));
|
|
996
|
+
return res;
|
|
997
|
+
});
|
|
979
998
|
}, (am, exn) => Logging.error({
|
|
980
999
|
err: Utils.prettifyExn(exn),
|
|
981
1000
|
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`,
|
|
@@ -986,7 +1005,7 @@ function make(param) {
|
|
|
986
1005
|
suggestedFix: "This likely means the RPC url you are using is not responding correctly. Please try another RPC endipoint."
|
|
987
1006
|
}
|
|
988
1007
|
}), undefined, undefined, undefined, undefined);
|
|
989
|
-
let makeBlockLoader = () => LazyLoader.make(blockNumber => getKnownRawBlockWithBackoff(client, name, chain, blockNumber, 1000), (am, exn) => Logging.error({
|
|
1008
|
+
let makeBlockLoader = () => LazyLoader.make(blockNumber => getKnownRawBlockWithBackoff(client, name, chain, blockNumber, 1000, recordRequest), (am, exn) => Logging.error({
|
|
990
1009
|
err: Utils.prettifyExn(exn),
|
|
991
1010
|
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`,
|
|
992
1011
|
source: name,
|
|
@@ -997,8 +1016,11 @@ function make(param) {
|
|
|
997
1016
|
}
|
|
998
1017
|
}), undefined, undefined, undefined, undefined);
|
|
999
1018
|
let makeReceiptLoader = () => LazyLoader.make(transactionHash => {
|
|
1000
|
-
|
|
1001
|
-
return Rest.fetch(Rpc.GetTransactionReceipt.rawRoute, transactionHash, client)
|
|
1019
|
+
let timerRef = Performance.now();
|
|
1020
|
+
return Rest.fetch(Rpc.GetTransactionReceipt.rawRoute, transactionHash, client).then(res => {
|
|
1021
|
+
recordRequest("eth_getTransactionReceipt", Performance.secondsSince(timerRef));
|
|
1022
|
+
return res;
|
|
1023
|
+
});
|
|
1002
1024
|
}, (am, exn) => Logging.error({
|
|
1003
1025
|
err: Utils.prettifyExn(exn),
|
|
1004
1026
|
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`,
|
|
@@ -1049,7 +1071,7 @@ function make(param) {
|
|
|
1049
1071
|
let firstBlockParentPromise = fromBlock > 0 ? LazyLoader.get(blockLoader.contents, fromBlock - 1 | 0).then(json => parseBlockInfo(json)) : Promise.resolve(undefined);
|
|
1050
1072
|
let match = getSelectionConfig(selection);
|
|
1051
1073
|
let logSelections = match.getLogSelectionsOrThrow(addressesByContractName);
|
|
1052
|
-
let match$1 = await getNextPage(fromBlock, suggestedToBlock, logSelections, blockNumber => LazyLoader.get(blockLoader.contents, blockNumber).then(parseBlockInfo), syncConfig, rpcClient, mutSuggestedBlockIntervals, partitionId,
|
|
1074
|
+
let match$1 = await getNextPage(fromBlock, suggestedToBlock, logSelections, blockNumber => LazyLoader.get(blockLoader.contents, blockNumber).then(parseBlockInfo), syncConfig, rpcClient, mutSuggestedBlockIntervals, partitionId, recordRequest);
|
|
1053
1075
|
let latestFetchedBlockInfo = match$1.latestFetchedBlockInfo;
|
|
1054
1076
|
let items = match$1.items;
|
|
1055
1077
|
let executedBlockInterval = (suggestedToBlock - fromBlock | 0) + 1 | 0;
|
|
@@ -1060,10 +1082,11 @@ function make(param) {
|
|
|
1060
1082
|
let log = param.log;
|
|
1061
1083
|
let topic0 = Stdlib_Option.getOr(log.topics[0], "0x0");
|
|
1062
1084
|
let routedAddress = lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(log.address) : Address.Evm.fromAddressOrThrow(log.address);
|
|
1063
|
-
let
|
|
1064
|
-
if (
|
|
1085
|
+
let onEventRegistration = EventRouter.get(eventRouter, EventRouter.getEvmEventId(topic0, log.topics.length), routedAddress, contractNameByAddress);
|
|
1086
|
+
if (onEventRegistration === undefined) {
|
|
1065
1087
|
return;
|
|
1066
1088
|
}
|
|
1089
|
+
let eventConfig = onEventRegistration.eventConfig;
|
|
1067
1090
|
let decoded = Stdlib_Option.flatMap(Primitive_option.fromNullable(param.params), __x => __x[eventConfig.contractName]);
|
|
1068
1091
|
if (decoded === undefined) {
|
|
1069
1092
|
return;
|
|
@@ -1110,11 +1133,9 @@ function make(param) {
|
|
|
1110
1133
|
let block = match[0];
|
|
1111
1134
|
return {
|
|
1112
1135
|
kind: 0,
|
|
1113
|
-
|
|
1114
|
-
timestamp: block.timestamp,
|
|
1136
|
+
onEventRegistration: onEventRegistration,
|
|
1115
1137
|
chain: chain,
|
|
1116
1138
|
blockNumber: block.number,
|
|
1117
|
-
blockHash: block.hash,
|
|
1118
1139
|
logIndex: log.logIndex,
|
|
1119
1140
|
transactionIndex: log.transactionIndex,
|
|
1120
1141
|
payload: {
|
|
@@ -1125,7 +1146,7 @@ function make(param) {
|
|
|
1125
1146
|
srcAddress: routedAddress,
|
|
1126
1147
|
logIndex: log.logIndex,
|
|
1127
1148
|
transaction: Primitive_option.some(match[1]),
|
|
1128
|
-
block: block
|
|
1149
|
+
block: Primitive_option.some(block)
|
|
1129
1150
|
}
|
|
1130
1151
|
};
|
|
1131
1152
|
})();
|
|
@@ -1162,12 +1183,14 @@ function make(param) {
|
|
|
1162
1183
|
blockHashes: blockHashes,
|
|
1163
1184
|
parsedQueueItems: parsedQueueItems,
|
|
1164
1185
|
transactionStore: undefined,
|
|
1186
|
+
blockStore: undefined,
|
|
1165
1187
|
fromBlockQueried: fromBlock,
|
|
1166
1188
|
latestFetchedBlockNumber: latestFetchedBlockInfo.number,
|
|
1167
1189
|
latestFetchedBlockTimestamp: latestFetchedBlockInfo.timestamp,
|
|
1168
1190
|
stats: {
|
|
1169
1191
|
"total time elapsed (s)": totalTimeElapsed
|
|
1170
|
-
}
|
|
1192
|
+
},
|
|
1193
|
+
requestStats: drainRequestStats()
|
|
1171
1194
|
};
|
|
1172
1195
|
};
|
|
1173
1196
|
let onReorg = param => {
|
|
@@ -1175,19 +1198,28 @@ function make(param) {
|
|
|
1175
1198
|
transactionLoader.contents = makeTransactionLoader();
|
|
1176
1199
|
receiptLoader.contents = makeReceiptLoader();
|
|
1177
1200
|
};
|
|
1178
|
-
let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks =>
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1201
|
+
let getBlockHashes = (blockNumbers, _currentlyUnusedLogger) => Stdlib_Promise.$$catch(Promise.all(blockNumbers.map(blockNum => LazyLoader.get(blockLoader.contents, blockNum))).then(rawBlocks => {
|
|
1202
|
+
let result = {
|
|
1203
|
+
TAG: "Ok",
|
|
1204
|
+
_0: rawBlocks.map(json => {
|
|
1205
|
+
let b = parseBlockInfo(json);
|
|
1206
|
+
return {
|
|
1207
|
+
blockHash: b.hash,
|
|
1208
|
+
blockNumber: b.number,
|
|
1209
|
+
blockTimestamp: b.timestamp
|
|
1210
|
+
};
|
|
1211
|
+
})
|
|
1212
|
+
};
|
|
1213
|
+
return {
|
|
1214
|
+
result: result,
|
|
1215
|
+
requestStats: drainRequestStats()
|
|
1216
|
+
};
|
|
1217
|
+
}), exn => Promise.resolve({
|
|
1218
|
+
result: {
|
|
1219
|
+
TAG: "Error",
|
|
1220
|
+
_0: exn
|
|
1221
|
+
},
|
|
1222
|
+
requestStats: drainRequestStats()
|
|
1191
1223
|
}));
|
|
1192
1224
|
let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => (onHeight => RpcWebSocketHeightStream.subscribe(wsUrl, chain, onHeight)));
|
|
1193
1225
|
return {
|
|
@@ -1203,15 +1235,14 @@ function make(param) {
|
|
|
1203
1235
|
try {
|
|
1204
1236
|
height = await rpcClient.getHeight();
|
|
1205
1237
|
} catch (exn) {
|
|
1206
|
-
|
|
1207
|
-
Prometheus.SourceRequestCount.increment(name, chain, "eth_blockNumber");
|
|
1208
|
-
Prometheus.SourceRequestCount.addSeconds(name, chain, "eth_blockNumber", seconds);
|
|
1238
|
+
recordRequest("eth_blockNumber", Performance.secondsSince(timerRef));
|
|
1209
1239
|
throw exn;
|
|
1210
1240
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1241
|
+
recordRequest("eth_blockNumber", Performance.secondsSince(timerRef));
|
|
1242
|
+
return {
|
|
1243
|
+
height: height,
|
|
1244
|
+
requestStats: drainRequestStats()
|
|
1245
|
+
};
|
|
1215
1246
|
},
|
|
1216
1247
|
getItemsOrThrow: getItemsOrThrow,
|
|
1217
1248
|
createHeightSubscription: createHeightSubscription,
|
|
@@ -108,11 +108,6 @@ let subscribe = (~wsUrl, ~chainId, ~onHeight: int => unit): (unit => unit) => {
|
|
|
108
108
|
| NewHead(blockNumber) =>
|
|
109
109
|
errorCount := 0
|
|
110
110
|
resetStaleTimeout()
|
|
111
|
-
Prometheus.SourceRequestCount.increment(
|
|
112
|
-
~sourceName="WebSocket",
|
|
113
|
-
~chainId,
|
|
114
|
-
~method="eth_subscribe",
|
|
115
|
-
)
|
|
116
111
|
onHeight(blockNumber)
|
|
117
112
|
| SubscriptionConfirmed(_) => resetStaleTimeout()
|
|
118
113
|
| ErrorResponse =>
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import * as Rpc from "./Rpc.res.mjs";
|
|
4
4
|
import * as Utils from "../Utils.res.mjs";
|
|
5
5
|
import * as Logging from "../Logging.res.mjs";
|
|
6
|
-
import * as Prometheus from "../Prometheus.res.mjs";
|
|
7
6
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
8
7
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
9
8
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
@@ -105,7 +104,6 @@ function subscribe(wsUrl, chainId, onHeight) {
|
|
|
105
104
|
}
|
|
106
105
|
errorCount.contents = 0;
|
|
107
106
|
resetStaleTimeout();
|
|
108
|
-
Prometheus.SourceRequestCount.increment("WebSocket", chainId, "eth_subscribe");
|
|
109
107
|
return onHeight(blockNumber._0);
|
|
110
108
|
} catch (raw_e) {
|
|
111
109
|
let e = Primitive_exceptions.internalToException(raw_e);
|
|
@@ -12,11 +12,11 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
|
|
|
12
12
|
poweredByHyperSync: false,
|
|
13
13
|
pollingInterval: 0,
|
|
14
14
|
getBlockHashes: (~blockNumbers as _, ~logger as _) => {
|
|
15
|
-
Promise.resolve(Ok([]))
|
|
15
|
+
Promise.resolve({Source.result: Ok([]), requestStats: []})
|
|
16
16
|
},
|
|
17
17
|
getHeightOrThrow: () => {
|
|
18
18
|
// Report at least height 1 so the engine doesn't treat 0 as "no blocks available"
|
|
19
|
-
Promise.resolve(max(endBlock, 1))
|
|
19
|
+
Promise.resolve({Source.height: max(endBlock, 1), requestStats: []})
|
|
20
20
|
},
|
|
21
21
|
getItemsOrThrow: (
|
|
22
22
|
~fromBlock as _,
|
|
@@ -43,14 +43,16 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
|
|
|
43
43
|
Source.knownHeight: reportedHeight,
|
|
44
44
|
blockHashes: [],
|
|
45
45
|
parsedQueueItems: result,
|
|
46
|
-
// Simulate keeps the transaction inline on the payload; no store
|
|
46
|
+
// Simulate keeps the transaction and block inline on the payload; no store pages.
|
|
47
47
|
transactionStore: None,
|
|
48
|
+
blockStore: None,
|
|
48
49
|
fromBlockQueried: 0,
|
|
49
50
|
latestFetchedBlockNumber: reportedHeight,
|
|
50
51
|
latestFetchedBlockTimestamp: 0,
|
|
51
52
|
stats: {
|
|
52
53
|
totalTimeElapsed: 0.,
|
|
53
54
|
},
|
|
55
|
+
requestStats: [],
|
|
54
56
|
})
|
|
55
57
|
},
|
|
56
58
|
}
|