envio 3.0.0-alpha.10 → 3.0.0-alpha.12
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/evm.schema.json +18 -0
- package/index.d.ts +13 -0
- package/package.json +5 -5
- package/src/Batch.res +2 -0
- package/src/Batch.res.mjs +1 -0
- package/src/ChainManager.res +3 -1
- package/src/ChainManager.res.mjs +1 -1
- package/src/Config.res +7 -1
- package/src/Config.res.mjs +6 -3
- package/src/Env.res +1 -0
- package/src/Env.res.mjs +4 -1
- package/src/GlobalState.res +0 -1
- package/src/GlobalState.res.mjs +0 -1
- package/src/PgStorage.res +2 -1
- package/src/PgStorage.res.mjs +2 -1
- package/src/Prometheus.res +12 -0
- package/src/Prometheus.res.mjs +45 -30
- package/src/TestIndexer.res +76 -4
- package/src/TestIndexer.res.mjs +144 -100
- package/src/Utils.res +22 -0
- package/src/Utils.res.mjs +18 -0
- package/src/db/InternalTable.res +5 -3
- package/src/db/InternalTable.res.mjs +6 -4
- package/src/sources/EvmChain.res +3 -0
- package/src/sources/EvmChain.res.mjs +2 -1
- package/src/sources/HyperFuelSource.res +5 -1
- package/src/sources/HyperFuelSource.res.mjs +5 -1
- package/src/sources/HyperSync.res +12 -3
- package/src/sources/HyperSync.res.mjs +9 -7
- package/src/sources/HyperSync.resi +4 -0
- package/src/sources/HyperSyncHeightStream.res +3 -1
- package/src/sources/HyperSyncHeightStream.res.mjs +3 -1
- package/src/sources/HyperSyncSource.res +10 -3
- package/src/sources/HyperSyncSource.res.mjs +8 -4
- package/src/sources/Rpc.res +21 -21
- package/src/sources/Rpc.res.mjs +18 -18
- package/src/sources/RpcSource.res +51 -56
- package/src/sources/RpcSource.res.mjs +50 -53
- package/src/sources/Svm.res +15 -2
- package/src/sources/Svm.res.mjs +7 -1
package/src/TestIndexer.res.mjs
CHANGED
|
@@ -253,6 +253,34 @@ function validateBlockRange(chainId, configChain, processChainConfig, progressBl
|
|
|
253
253
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
function makeEntityGet(state, entityConfig) {
|
|
257
|
+
return function (entityId) {
|
|
258
|
+
if (state.processInProgress) {
|
|
259
|
+
Js_exn.raiseError("Cannot call " + entityConfig.name + ".get() while indexer.process() is running. Wait for process() to complete before accessing entities directly.");
|
|
260
|
+
}
|
|
261
|
+
var entityDict = Belt_Option.getWithDefault(Js_dict.get(state.entities, entityConfig.name), {});
|
|
262
|
+
return Promise.resolve(Js_dict.get(entityDict, entityId));
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function makeEntitySet(state, entityConfig) {
|
|
267
|
+
return function (entity) {
|
|
268
|
+
if (state.processInProgress) {
|
|
269
|
+
Js_exn.raiseError("Cannot call " + entityConfig.name + ".set() while indexer.process() is running. Wait for process() to complete before modifying entities directly.");
|
|
270
|
+
}
|
|
271
|
+
var dict = Js_dict.get(state.entities, entityConfig.name);
|
|
272
|
+
var entityDict;
|
|
273
|
+
if (dict !== undefined) {
|
|
274
|
+
entityDict = dict;
|
|
275
|
+
} else {
|
|
276
|
+
var dict$1 = {};
|
|
277
|
+
state.entities[entityConfig.name] = dict$1;
|
|
278
|
+
entityDict = dict$1;
|
|
279
|
+
}
|
|
280
|
+
entityDict[entity.id] = entity;
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
256
284
|
function makeCreateTestIndexer(config, workerPath, allEntities) {
|
|
257
285
|
return function () {
|
|
258
286
|
var entities = {};
|
|
@@ -268,111 +296,125 @@ function makeCreateTestIndexer(config, workerPath, allEntities) {
|
|
|
268
296
|
entityConfigs: entityConfigs,
|
|
269
297
|
processChanges: []
|
|
270
298
|
};
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
299
|
+
var entityOpsDict = {};
|
|
300
|
+
Belt_Array.forEach(allEntities, (function (entityConfig) {
|
|
301
|
+
if (entityConfig.name !== InternalTable.DynamicContractRegistry.name) {
|
|
302
|
+
entityOpsDict[entityConfig.name] = {
|
|
303
|
+
get: makeEntityGet(state, entityConfig),
|
|
304
|
+
set: makeEntitySet(state, entityConfig)
|
|
305
|
+
};
|
|
306
|
+
return ;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
}));
|
|
310
|
+
var result = {};
|
|
311
|
+
Belt_Array.forEach(Js_dict.entries(entityOpsDict), (function (param) {
|
|
312
|
+
result[param[0]] = param[1];
|
|
313
|
+
}));
|
|
314
|
+
result["process"] = (function (processConfig) {
|
|
315
|
+
if (state.processInProgress) {
|
|
316
|
+
Js_exn.raiseError("createTestIndexer process is already running. Only one process call is allowed at a time");
|
|
317
|
+
}
|
|
318
|
+
var chains = processConfig.chains;
|
|
319
|
+
var chainKeys = Object.keys(chains);
|
|
320
|
+
var n = chainKeys.length;
|
|
321
|
+
if (n !== 0) {
|
|
322
|
+
if (n !== 1) {
|
|
323
|
+
Js_exn.raiseError("createTestIndexer does not support processing multiple chains at once. Found " + String(n) + " chains defined");
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
} else {
|
|
327
|
+
Js_exn.raiseError("createTestIndexer requires exactly one chain to be defined");
|
|
328
|
+
}
|
|
329
|
+
Belt_Array.forEach(chainKeys, (function (chainIdStr) {
|
|
330
|
+
var chainId = Belt_Option.getWithDefault(Belt_Int.fromString(chainIdStr), 0);
|
|
331
|
+
var chain = ChainMap.Chain.makeUnsafe(chainId);
|
|
332
|
+
var configChain = ChainMap.get(config.chainMap, chain);
|
|
333
|
+
var processChainConfig = chains[chainIdStr];
|
|
334
|
+
var progressBlock = Js_dict.get(state.progressBlockByChain, chainIdStr);
|
|
335
|
+
validateBlockRange(chainIdStr, configChain, processChainConfig, progressBlock);
|
|
336
|
+
}));
|
|
337
|
+
state.processChanges = [];
|
|
338
|
+
var dynamicContractsByChain = {};
|
|
339
|
+
var dcDict = Js_dict.get(state.entities, InternalTable.DynamicContractRegistry.name);
|
|
340
|
+
if (dcDict !== undefined) {
|
|
341
|
+
Belt_Array.forEach(Js_dict.values(dcDict), (function (entity) {
|
|
342
|
+
var chainIdStr = String(entity.chain_id);
|
|
343
|
+
var arr = Js_dict.get(dynamicContractsByChain, chainIdStr);
|
|
344
|
+
var contracts;
|
|
345
|
+
if (arr !== undefined) {
|
|
346
|
+
contracts = arr;
|
|
347
|
+
} else {
|
|
348
|
+
var arr$1 = [];
|
|
349
|
+
dynamicContractsByChain[chainIdStr] = arr$1;
|
|
350
|
+
contracts = arr$1;
|
|
282
351
|
}
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
var initialState = makeInitialState(config, chains, dynamicContractsByChain);
|
|
314
|
-
return new Promise((function (resolve, reject) {
|
|
315
|
-
var workerDataObj = {
|
|
316
|
-
processConfig: JSON.parse(Js_json.serializeExn(processConfig)),
|
|
317
|
-
initialState: initialState
|
|
318
|
-
};
|
|
319
|
-
var workerData = JSON.parse(Js_json.serializeExn(workerDataObj));
|
|
320
|
-
var worker;
|
|
321
|
-
try {
|
|
322
|
-
worker = new Worker_threads.Worker(workerPath, {
|
|
323
|
-
workerData: workerData
|
|
352
|
+
contracts.push(toIndexingContract(entity));
|
|
353
|
+
}));
|
|
354
|
+
}
|
|
355
|
+
var initialState = makeInitialState(config, chains, dynamicContractsByChain);
|
|
356
|
+
return new Promise((function (resolve, reject) {
|
|
357
|
+
var workerDataObj = {
|
|
358
|
+
processConfig: JSON.parse(Js_json.serializeExn(processConfig)),
|
|
359
|
+
initialState: initialState
|
|
360
|
+
};
|
|
361
|
+
var workerData = JSON.parse(Js_json.serializeExn(workerDataObj));
|
|
362
|
+
var worker;
|
|
363
|
+
try {
|
|
364
|
+
worker = new Worker_threads.Worker(workerPath, {
|
|
365
|
+
workerData: workerData
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
catch (raw_exn){
|
|
369
|
+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
370
|
+
reject(exn);
|
|
371
|
+
throw exn;
|
|
372
|
+
}
|
|
373
|
+
state.processInProgress = true;
|
|
374
|
+
worker.on("message", (function (msg) {
|
|
375
|
+
var respond = function (data) {
|
|
376
|
+
worker.postMessage({
|
|
377
|
+
id: msg.id,
|
|
378
|
+
payload: {
|
|
379
|
+
type: "response",
|
|
380
|
+
data: data
|
|
381
|
+
}
|
|
324
382
|
});
|
|
383
|
+
};
|
|
384
|
+
var match = msg.payload;
|
|
385
|
+
switch (match.type) {
|
|
386
|
+
case "loadByIds" :
|
|
387
|
+
return respond(handleLoadByIds(state, match.tableName, match.ids));
|
|
388
|
+
case "loadByField" :
|
|
389
|
+
return respond(handleLoadByField(state, match.tableName, match.fieldName, match.fieldValue, match.operator));
|
|
390
|
+
case "writeBatch" :
|
|
391
|
+
handleWriteBatch(state, match.updatedEntities, match.checkpointIds, match.checkpointChainIds, match.checkpointBlockNumbers, match.checkpointBlockHashes, match.checkpointEventsProcessed);
|
|
392
|
+
return respond(null);
|
|
393
|
+
|
|
325
394
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
395
|
+
}));
|
|
396
|
+
worker.on("error", (function (err) {
|
|
397
|
+
state.processInProgress = false;
|
|
398
|
+
worker.terminate();
|
|
399
|
+
reject(err);
|
|
400
|
+
}));
|
|
401
|
+
worker.on("exit", (function (code) {
|
|
402
|
+
state.processInProgress = false;
|
|
403
|
+
if (code !== 0) {
|
|
404
|
+
return reject(new Error("Worker exited with code " + String(code)));
|
|
405
|
+
} else {
|
|
406
|
+
Belt_Array.forEach(chainKeys, (function (chainIdStr) {
|
|
407
|
+
var processChainConfig = chains[chainIdStr];
|
|
408
|
+
state.progressBlockByChain[chainIdStr] = processChainConfig.endBlock;
|
|
409
|
+
}));
|
|
410
|
+
return resolve({
|
|
411
|
+
changes: state.processChanges
|
|
412
|
+
});
|
|
330
413
|
}
|
|
331
|
-
state.processInProgress = true;
|
|
332
|
-
worker.on("message", (function (msg) {
|
|
333
|
-
var respond = function (data) {
|
|
334
|
-
worker.postMessage({
|
|
335
|
-
id: msg.id,
|
|
336
|
-
payload: {
|
|
337
|
-
type: "response",
|
|
338
|
-
data: data
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
};
|
|
342
|
-
var match = msg.payload;
|
|
343
|
-
switch (match.type) {
|
|
344
|
-
case "loadByIds" :
|
|
345
|
-
return respond(handleLoadByIds(state, match.tableName, match.ids));
|
|
346
|
-
case "loadByField" :
|
|
347
|
-
return respond(handleLoadByField(state, match.tableName, match.fieldName, match.fieldValue, match.operator));
|
|
348
|
-
case "writeBatch" :
|
|
349
|
-
handleWriteBatch(state, match.updatedEntities, match.checkpointIds, match.checkpointChainIds, match.checkpointBlockNumbers, match.checkpointBlockHashes, match.checkpointEventsProcessed);
|
|
350
|
-
return respond(null);
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
}));
|
|
354
|
-
worker.on("error", (function (err) {
|
|
355
|
-
state.processInProgress = false;
|
|
356
|
-
worker.terminate();
|
|
357
|
-
reject(err);
|
|
358
|
-
}));
|
|
359
|
-
worker.on("exit", (function (code) {
|
|
360
|
-
state.processInProgress = false;
|
|
361
|
-
if (code !== 0) {
|
|
362
|
-
return reject(new Error("Worker exited with code " + String(code)));
|
|
363
|
-
} else {
|
|
364
|
-
Belt_Array.forEach(chainKeys, (function (chainIdStr) {
|
|
365
|
-
var processChainConfig = chains[chainIdStr];
|
|
366
|
-
state.progressBlockByChain[chainIdStr] = processChainConfig.endBlock;
|
|
367
|
-
}));
|
|
368
|
-
return resolve({
|
|
369
|
-
changes: state.processChanges
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
}));
|
|
373
414
|
}));
|
|
374
|
-
|
|
375
|
-
|
|
415
|
+
}));
|
|
416
|
+
});
|
|
417
|
+
return result;
|
|
376
418
|
};
|
|
377
419
|
}
|
|
378
420
|
|
|
@@ -406,6 +448,8 @@ export {
|
|
|
406
448
|
handleWriteBatch ,
|
|
407
449
|
makeInitialState ,
|
|
408
450
|
validateBlockRange ,
|
|
451
|
+
makeEntityGet ,
|
|
452
|
+
makeEntitySet ,
|
|
409
453
|
makeCreateTestIndexer ,
|
|
410
454
|
initTestWorker ,
|
|
411
455
|
}
|
package/src/Utils.res
CHANGED
|
@@ -435,6 +435,28 @@ String.replaceAll("the cat and the dog", "the", "this") == "this cat and this do
|
|
|
435
435
|
external replaceAll: (string, string, string) => string = "replaceAll"
|
|
436
436
|
}
|
|
437
437
|
|
|
438
|
+
module Url = {
|
|
439
|
+
/**
|
|
440
|
+
Extracts the hostname from a URL string.
|
|
441
|
+
Returns None if the URL doesn't have a valid http:// or https:// protocol.
|
|
442
|
+
*/
|
|
443
|
+
let getHostFromUrl = (url: string) => {
|
|
444
|
+
// Regular expression requiring protocol and capturing hostname
|
|
445
|
+
// - (https?:\/\/) : Required http:// or https:// (capturing group)
|
|
446
|
+
// - ([^\/?]+) : Capture hostname (one or more characters that aren't / or ?)
|
|
447
|
+
// - .* : Match rest of the string
|
|
448
|
+
let regex = %re("/https?:\/\/([^\/?]+).*/")
|
|
449
|
+
switch Js.Re.exec_(regex, url) {
|
|
450
|
+
| Some(result) =>
|
|
451
|
+
switch Js.Re.captures(result)->Belt.Array.get(1) {
|
|
452
|
+
| Some(host) => host->Js.Nullable.toOption
|
|
453
|
+
| None => None
|
|
454
|
+
}
|
|
455
|
+
| None => None
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
438
460
|
module Result = {
|
|
439
461
|
let forEach = (result, fn) => {
|
|
440
462
|
switch result {
|
package/src/Utils.res.mjs
CHANGED
|
@@ -389,6 +389,23 @@ var $$String = {
|
|
|
389
389
|
capitalize: capitalize
|
|
390
390
|
};
|
|
391
391
|
|
|
392
|
+
function getHostFromUrl(url) {
|
|
393
|
+
var regex = /https?:\/\/([^\/?]+).*/;
|
|
394
|
+
var result = regex.exec(url);
|
|
395
|
+
if (result === null) {
|
|
396
|
+
return ;
|
|
397
|
+
}
|
|
398
|
+
var host = Belt_Array.get(result, 1);
|
|
399
|
+
if (host !== undefined) {
|
|
400
|
+
return Caml_option.nullable_to_opt(Caml_option.valFromOption(host));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
var Url = {
|
|
406
|
+
getHostFromUrl: getHostFromUrl
|
|
407
|
+
};
|
|
408
|
+
|
|
392
409
|
function forEach$1(result, fn) {
|
|
393
410
|
if (result.TAG === "Ok") {
|
|
394
411
|
fn(result._0);
|
|
@@ -643,6 +660,7 @@ export {
|
|
|
643
660
|
UnsafeIntOperators ,
|
|
644
661
|
$$Array$1 as $$Array,
|
|
645
662
|
$$String ,
|
|
663
|
+
Url ,
|
|
646
664
|
Result ,
|
|
647
665
|
unwrapResultExn ,
|
|
648
666
|
Schema ,
|
package/src/db/InternalTable.res
CHANGED
|
@@ -74,6 +74,7 @@ module Chains = {
|
|
|
74
74
|
type progressFields = [
|
|
75
75
|
| #progress_block
|
|
76
76
|
| #events_processed
|
|
77
|
+
| #source_block
|
|
77
78
|
]
|
|
78
79
|
|
|
79
80
|
type field = [
|
|
@@ -108,7 +109,6 @@ module Chains = {
|
|
|
108
109
|
type metaFields = {
|
|
109
110
|
@as("first_event_block") firstEventBlockNumber: Js.null<int>,
|
|
110
111
|
@as("buffer_block") latestFetchedBlockNumber: int,
|
|
111
|
-
@as("source_block") blockHeight: int,
|
|
112
112
|
@as("ready_at")
|
|
113
113
|
timestampCaughtUpToHeadOrEndblock: Js.null<Js.Date.t>,
|
|
114
114
|
@as("_is_hyper_sync") isHyperSync: bool,
|
|
@@ -122,6 +122,7 @@ module Chains = {
|
|
|
122
122
|
@as("max_reorg_depth") maxReorgDepth: int,
|
|
123
123
|
@as("progress_block") progressBlockNumber: int,
|
|
124
124
|
@as("events_processed") numEventsProcessed: int,
|
|
125
|
+
@as("source_block") blockHeight: int,
|
|
125
126
|
...metaFields,
|
|
126
127
|
}
|
|
127
128
|
|
|
@@ -212,7 +213,6 @@ VALUES ${valuesRows->Js.Array2.joinWith(",\n ")};`,
|
|
|
212
213
|
|
|
213
214
|
// Fields that can be updated outside of the batch transaction
|
|
214
215
|
let metaFields: array<field> = [
|
|
215
|
-
#source_block,
|
|
216
216
|
#buffer_block,
|
|
217
217
|
#first_event_block,
|
|
218
218
|
#ready_at,
|
|
@@ -279,7 +279,7 @@ FROM "${pgSchema}"."${table.tableName}" as chains;`
|
|
|
279
279
|
->(Utils.magic: promise<array<unknown>> => promise<array<rawInitialState>>)
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
let progressFields: array<progressFields> = [#progress_block, #events_processed]
|
|
282
|
+
let progressFields: array<progressFields> = [#progress_block, #events_processed, #source_block]
|
|
283
283
|
|
|
284
284
|
let makeProgressFieldsUpdateQuery = (~pgSchema) => {
|
|
285
285
|
let setClauses = Belt.Array.mapWithIndex(progressFields, (index, field) => {
|
|
@@ -320,6 +320,7 @@ WHERE "id" = $1;`
|
|
|
320
320
|
type progressedChain = {
|
|
321
321
|
chainId: int,
|
|
322
322
|
progressBlockNumber: int,
|
|
323
|
+
sourceBlockNumber: int,
|
|
323
324
|
totalEventsProcessed: int,
|
|
324
325
|
}
|
|
325
326
|
|
|
@@ -341,6 +342,7 @@ WHERE "id" = $1;`
|
|
|
341
342
|
switch field {
|
|
342
343
|
| #progress_block => data.progressBlockNumber->(Utils.magic: int => unknown)
|
|
343
344
|
| #events_processed => data.totalEventsProcessed->(Utils.magic: int => unknown)
|
|
345
|
+
| #source_block => data.sourceBlockNumber->(Utils.magic: int => unknown)
|
|
344
346
|
},
|
|
345
347
|
)
|
|
346
348
|
->ignore
|
|
@@ -101,9 +101,9 @@ function initialFromConfig(chainConfig) {
|
|
|
101
101
|
max_reorg_depth: chainConfig.maxReorgDepth,
|
|
102
102
|
progress_block: -1,
|
|
103
103
|
events_processed: 0,
|
|
104
|
+
source_block: 0,
|
|
104
105
|
first_event_block: null,
|
|
105
106
|
buffer_block: -1,
|
|
106
|
-
source_block: 0,
|
|
107
107
|
ready_at: null,
|
|
108
108
|
_is_hyper_sync: false,
|
|
109
109
|
_num_batches_fetched: 0
|
|
@@ -143,7 +143,6 @@ function makeInitialValuesQuery(pgSchema, chainConfigs) {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
var metaFields = [
|
|
146
|
-
"source_block",
|
|
147
146
|
"buffer_block",
|
|
148
147
|
"first_event_block",
|
|
149
148
|
"ready_at",
|
|
@@ -169,7 +168,8 @@ function getInitialState(sql, pgSchema) {
|
|
|
169
168
|
|
|
170
169
|
var progressFields = [
|
|
171
170
|
"progress_block",
|
|
172
|
-
"events_processed"
|
|
171
|
+
"events_processed",
|
|
172
|
+
"source_block"
|
|
173
173
|
];
|
|
174
174
|
|
|
175
175
|
function makeProgressFieldsUpdateQuery(pgSchema) {
|
|
@@ -202,7 +202,9 @@ function setProgressedChains(sql, pgSchema, progressedChains) {
|
|
|
202
202
|
var params = [];
|
|
203
203
|
params.push(data.chainId);
|
|
204
204
|
progressFields.forEach(function (field) {
|
|
205
|
-
params.push(field === "
|
|
205
|
+
params.push(field === "source_block" ? data.sourceBlockNumber : (
|
|
206
|
+
field === "progress_block" ? data.progressBlockNumber : data.totalEventsProcessed
|
|
207
|
+
));
|
|
206
208
|
});
|
|
207
209
|
promises.push(sql.unsafe(query, params, {prepare: true}));
|
|
208
210
|
});
|
package/src/sources/EvmChain.res
CHANGED
|
@@ -15,6 +15,7 @@ let getSyncConfig = (
|
|
|
15
15
|
?backoffMillis,
|
|
16
16
|
?queryTimeoutMillis,
|
|
17
17
|
?fallbackStallTimeout,
|
|
18
|
+
?pollingInterval,
|
|
18
19
|
}: Config.sourceSyncOptions,
|
|
19
20
|
): Config.sourceSync => {
|
|
20
21
|
let queryTimeoutMillis = queryTimeoutMillis->Option.getWithDefault(20_000)
|
|
@@ -39,6 +40,8 @@ let getSyncConfig = (
|
|
|
39
40
|
// How long to wait before cancelling an RPC request
|
|
40
41
|
queryTimeoutMillis,
|
|
41
42
|
fallbackStallTimeout: fallbackStallTimeout->Option.getWithDefault(queryTimeoutMillis / 2),
|
|
43
|
+
// How frequently to check for new blocks in realtime (default: 1000ms)
|
|
44
|
+
pollingInterval: pollingInterval->Option.getWithDefault(1000),
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
|
|
@@ -16,7 +16,8 @@ function getSyncConfig(param) {
|
|
|
16
16
|
intervalCeiling: Belt_Option.getWithDefault(Env.Configurable.SyncConfig.intervalCeiling, Belt_Option.getWithDefault(param.intervalCeiling, 10000)),
|
|
17
17
|
backoffMillis: Belt_Option.getWithDefault(param.backoffMillis, 5000),
|
|
18
18
|
queryTimeoutMillis: queryTimeoutMillis,
|
|
19
|
-
fallbackStallTimeout: Belt_Option.getWithDefault(param.fallbackStallTimeout, queryTimeoutMillis / 2 | 0)
|
|
19
|
+
fallbackStallTimeout: Belt_Option.getWithDefault(param.fallbackStallTimeout, queryTimeoutMillis / 2 | 0),
|
|
20
|
+
pollingInterval: Belt_Option.getWithDefault(param.pollingInterval, 1000)
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -235,6 +235,7 @@ let make = ({chain, endpointUrl}: options): t => {
|
|
|
235
235
|
let startFetchingBatchTimeRef = Hrtime.makeTimer()
|
|
236
236
|
|
|
237
237
|
//fetch batch
|
|
238
|
+
Prometheus.SourceRequestCount.increment(~sourceName=name, ~chainId=chain->ChainMap.Chain.toChainId)
|
|
238
239
|
let pageUnsafe = try await HyperFuel.GetLogs.query(
|
|
239
240
|
~serverUrl=endpointUrl,
|
|
240
241
|
~fromBlock,
|
|
@@ -496,7 +497,10 @@ let make = ({chain, endpointUrl}: options): t => {
|
|
|
496
497
|
getBlockHashes,
|
|
497
498
|
pollingInterval: 100,
|
|
498
499
|
poweredByHyperSync: true,
|
|
499
|
-
getHeightOrThrow: () =>
|
|
500
|
+
getHeightOrThrow: () => {
|
|
501
|
+
Prometheus.SourceRequestCount.increment(~sourceName=name, ~chainId=chain->ChainMap.Chain.toChainId)
|
|
502
|
+
HyperFuel.heightRoute->Rest.fetch((), ~client=jsonApiClient)
|
|
503
|
+
},
|
|
500
504
|
getItemsOrThrow,
|
|
501
505
|
}
|
|
502
506
|
}
|
|
@@ -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,6 +186,7 @@ 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
191
|
var getItemsOrThrow = async function (fromBlock, toBlock, addressesByContractName, indexingContracts, knownHeight, param, selection, retry, logger) {
|
|
190
192
|
var mkLogAndRaise = function (extra, extra$1) {
|
|
@@ -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);
|
|
197
200
|
var pageUnsafe;
|
|
198
201
|
try {
|
|
199
202
|
pageUnsafe = await HyperFuel.GetLogs.query(endpointUrl, fromBlock, toBlock, recieptsSelection);
|
|
@@ -421,13 +424,14 @@ 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
433
|
getHeightOrThrow: (function () {
|
|
434
|
+
Prometheus.SourceRequestCount.increment(name, chain);
|
|
431
435
|
return Rest.$$fetch(HyperFuel.heightRoute, undefined, jsonApiClient);
|
|
432
436
|
}),
|
|
433
437
|
getItemsOrThrow: getItemsOrThrow
|
|
@@ -245,6 +245,8 @@ module BlockData = {
|
|
|
245
245
|
~apiToken,
|
|
246
246
|
~fromBlock,
|
|
247
247
|
~toBlock,
|
|
248
|
+
~sourceName,
|
|
249
|
+
~chainId,
|
|
248
250
|
~logger,
|
|
249
251
|
): queryResponse<array<ReorgDetection.blockDataWithTimestamp>> => {
|
|
250
252
|
let body = makeRequestBody(~fromBlock, ~toBlock)
|
|
@@ -258,6 +260,7 @@ module BlockData = {
|
|
|
258
260
|
},
|
|
259
261
|
)
|
|
260
262
|
|
|
263
|
+
Prometheus.SourceRequestCount.increment(~sourceName, ~chainId)
|
|
261
264
|
let maybeSuccessfulRes = switch await Time.retryAsyncWithExponentialBackOff(() =>
|
|
262
265
|
HyperSyncJsonApi.queryRoute->Rest.fetch(
|
|
263
266
|
{
|
|
@@ -281,7 +284,7 @@ module BlockData = {
|
|
|
281
284
|
`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
285
|
)
|
|
283
286
|
await Time.resolvePromiseAfterDelay(~delayMilliseconds)
|
|
284
|
-
await queryBlockData(~serverUrl, ~apiToken, ~fromBlock, ~toBlock, ~logger)
|
|
287
|
+
await queryBlockData(~serverUrl, ~apiToken, ~fromBlock, ~toBlock, ~sourceName, ~chainId, ~logger)
|
|
285
288
|
}
|
|
286
289
|
| Some(res) =>
|
|
287
290
|
switch res->convertResponse {
|
|
@@ -292,6 +295,8 @@ module BlockData = {
|
|
|
292
295
|
~apiToken,
|
|
293
296
|
~fromBlock=res.nextBlock,
|
|
294
297
|
~toBlock,
|
|
298
|
+
~sourceName,
|
|
299
|
+
~chainId,
|
|
295
300
|
~logger,
|
|
296
301
|
)
|
|
297
302
|
restRes->Result.map(rest => datas->Array.concat(rest))
|
|
@@ -301,7 +306,7 @@ module BlockData = {
|
|
|
301
306
|
}
|
|
302
307
|
}
|
|
303
308
|
|
|
304
|
-
let queryBlockDataMulti = async (~serverUrl, ~apiToken, ~blockNumbers, ~logger) => {
|
|
309
|
+
let queryBlockDataMulti = async (~serverUrl, ~apiToken, ~blockNumbers, ~sourceName, ~chainId, ~logger) => {
|
|
305
310
|
switch blockNumbers->Array.get(0) {
|
|
306
311
|
| None => Ok([])
|
|
307
312
|
| Some(firstBlock) => {
|
|
@@ -328,6 +333,8 @@ module BlockData = {
|
|
|
328
333
|
~toBlock=toBlock.contents,
|
|
329
334
|
~serverUrl,
|
|
330
335
|
~apiToken,
|
|
336
|
+
~sourceName,
|
|
337
|
+
~chainId,
|
|
331
338
|
~logger,
|
|
332
339
|
)
|
|
333
340
|
let filtered = res->Result.map(datas => {
|
|
@@ -346,12 +353,14 @@ module BlockData = {
|
|
|
346
353
|
}
|
|
347
354
|
}
|
|
348
355
|
|
|
349
|
-
let queryBlockData = (~serverUrl, ~apiToken, ~blockNumber, ~logger) =>
|
|
356
|
+
let queryBlockData = (~serverUrl, ~apiToken, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
|
|
350
357
|
BlockData.queryBlockData(
|
|
351
358
|
~serverUrl,
|
|
352
359
|
~apiToken,
|
|
353
360
|
~fromBlock=blockNumber,
|
|
354
361
|
~toBlock=blockNumber,
|
|
362
|
+
~sourceName,
|
|
363
|
+
~chainId,
|
|
355
364
|
~logger,
|
|
356
365
|
)->Promise.thenResolve(res => res->Result.map(res => res->Array.get(0)))
|
|
357
366
|
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);
|
|
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
|
|