envio
Version:
A latency and sync speed optimized, developer friendly blockchain data indexer.
335 lines (313 loc) • 13.4 kB
JavaScript
// Generated by ReScript, PLEASE EDIT WITH CARE
;
var Rest = require("../vendored/Rest.res.js");
var Time = require("../Time.res.js");
var Utils = require("../Utils.res.js");
var $$BigInt = require("../bindings/BigInt.res.js");
var Js_exn = require("rescript/lib/js/js_exn.js");
var Logging = require("../Logging.res.js");
var Belt_Array = require("rescript/lib/js/belt_Array.js");
var Belt_Option = require("rescript/lib/js/belt_Option.js");
var Belt_Result = require("rescript/lib/js/belt_Result.js");
var Caml_option = require("rescript/lib/js/caml_option.js");
var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js");
var HyperSyncClient = require("./HyperSyncClient.res.js");
var HyperSyncJsonApi = require("./HyperSyncJsonApi.res.js");
var fieldNames = [
"address",
"data",
"topics",
"logIndex"
];
var HyperSyncQueryError = /* @__PURE__ */Caml_exceptions.create("HyperSync.HyperSyncQueryError");
function queryErrorToMsq(e) {
var match = e._0;
return match.queryName + " query failed due to unexpected missing params on response:\n " + match.missingParams.join(", ");
}
function mapExn(queryResponse) {
if (queryResponse.TAG === "Ok") {
return {
TAG: "Ok",
_0: queryResponse._0
};
} else {
return {
TAG: "Error",
_0: {
RE_EXN_ID: HyperSyncQueryError,
_1: queryResponse._0
}
};
}
}
var $$Error = /* @__PURE__ */Caml_exceptions.create("HyperSync.GetLogs.Error");
function makeRequestBody(fromBlock, toBlockInclusive, addressesWithTopics, fieldSelection) {
return {
fromBlock: fromBlock,
toBlock: toBlockInclusive !== undefined ? toBlockInclusive + 1 | 0 : undefined,
logs: addressesWithTopics,
fieldSelection: fieldSelection
};
}
async function query(client, fromBlock, toBlock, logSelections, fieldSelection, nonOptionalBlockFieldNames, nonOptionalTransactionFieldNames) {
var addressesWithTopics = Belt_Array.flatMap(logSelections, (function (param) {
var addresses = param.addresses;
return Belt_Array.map(param.topicSelections, (function (param) {
var topics = HyperSyncClient.QueryTypes.makeTopicSelection(param.topic0, param.topic1, param.topic2, param.topic3);
return HyperSyncClient.QueryTypes.makeLogSelection(addresses, topics);
}));
}));
var query$1 = makeRequestBody(fromBlock, toBlock, addressesWithTopics, fieldSelection);
var res = await client.getEvents(query$1);
if (res.nextBlock <= fromBlock) {
throw {
RE_EXN_ID: $$Error,
_1: "WrongInstance",
Error: new Error()
};
}
var items = Belt_Array.map(res.data, (function (item) {
var missingParams = [];
var returnedObj = item.log;
if (Utils.$$Array.notEmpty(fieldNames)) {
if (returnedObj) {
for(var idx = 0 ,idx_finish = fieldNames.length; idx < idx_finish; ++idx){
var fieldName = fieldNames[idx];
var match = returnedObj[fieldName];
if (match !== undefined) {
} else {
missingParams.push("log." + fieldName);
}
}
} else {
missingParams.push("log");
}
}
var returnedObj$1 = item.block;
if (Utils.$$Array.notEmpty(nonOptionalBlockFieldNames)) {
if (returnedObj$1) {
for(var idx$1 = 0 ,idx_finish$1 = nonOptionalBlockFieldNames.length; idx$1 < idx_finish$1; ++idx$1){
var fieldName$1 = nonOptionalBlockFieldNames[idx$1];
var match$1 = returnedObj$1[fieldName$1];
if (match$1 !== undefined) {
} else {
missingParams.push("block." + fieldName$1);
}
}
} else {
missingParams.push("block");
}
}
var returnedObj$2 = item.transaction;
if (Utils.$$Array.notEmpty(nonOptionalTransactionFieldNames)) {
if (returnedObj$2) {
for(var idx$2 = 0 ,idx_finish$2 = nonOptionalTransactionFieldNames.length; idx$2 < idx_finish$2; ++idx$2){
var fieldName$2 = nonOptionalTransactionFieldNames[idx$2];
var match$2 = returnedObj$2[fieldName$2];
if (match$2 !== undefined) {
} else {
missingParams.push("transaction." + fieldName$2);
}
}
} else {
missingParams.push("transaction");
}
}
if (missingParams.length !== 0) {
throw {
RE_EXN_ID: $$Error,
_1: {
TAG: "UnexpectedMissingParams",
missingParams: missingParams
},
Error: new Error()
};
}
var logUnsanitized = item.log;
var topics = Belt_Array.keepMap(item.log.topics, (function (prim) {
if (prim == null) {
return ;
} else {
return Caml_option.some(prim);
}
}));
var address = item.log.address;
var log_data = logUnsanitized.data;
var log_logIndex = logUnsanitized.logIndex;
var log = {
address: address,
data: log_data,
topics: topics,
logIndex: log_logIndex
};
return {
log: log,
block: item.block,
transaction: item.transaction
};
}));
return {
items: items,
nextBlock: res.nextBlock,
archiveHeight: Belt_Option.getWithDefault(res.archiveHeight, 0),
rollbackGuard: res.rollbackGuard,
events: res.data
};
}
function makeRequestBody$1(fromBlock, toBlock) {
return {
fromBlock: fromBlock,
toBlockExclusive: toBlock + 1 | 0,
fieldSelection: {
block: [
"number",
"hash",
"timestamp"
]
},
includeAllBlocks: true
};
}
function convertResponse(res) {
return Utils.$$Array.transposeResults(Belt_Array.flatMap(res.data, (function (item) {
return Belt_Option.mapWithDefault(item.blocks, [], (function (blocks) {
return Belt_Array.map(blocks, (function (block) {
var blockNumber = block.number;
if (blockNumber !== undefined) {
var blockHash = block.hash;
if (blockHash !== undefined) {
var timestamp = block.timestamp;
if (timestamp !== undefined) {
var blockTimestamp = Belt_Option.getExn($$BigInt.toInt(timestamp));
return {
TAG: "Ok",
_0: {
blockHash: blockHash,
blockNumber: blockNumber,
blockTimestamp: blockTimestamp
}
};
}
}
}
var missingParams = Belt_Array.keepMap([
Utils.$$Option.mapNone(block.number, "block.number"),
Utils.$$Option.mapNone(block.timestamp, "block.timestamp"),
Utils.$$Option.mapNone(block.hash, "block.hash")
], (function (p) {
return p;
}));
return {
TAG: "Error",
_0: {
TAG: "UnexpectedMissingParams",
_0: {
queryName: "query block data HyperSync",
missingParams: missingParams
}
}
};
}));
}));
})));
}
async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger) {
var body = makeRequestBody$1(fromBlock, toBlock);
var logger$1 = Logging.createChildFrom(logger, {
logType: "HyperSync get block hash query",
fromBlock: fromBlock,
toBlock: toBlock
});
var maybeSuccessfulRes;
var exit = 0;
var res;
try {
res = await Time.retryAsyncWithExponentialBackOff(undefined, undefined, undefined, undefined, logger$1, (function () {
return Rest.$$fetch(HyperSyncJsonApi.queryRoute, {
query: body,
token: apiToken
}, Rest.client(serverUrl, undefined));
}));
exit = 1;
}
catch (exn){
maybeSuccessfulRes = undefined;
}
if (exit === 1) {
maybeSuccessfulRes = res.nextBlock <= fromBlock ? undefined : res;
}
if (maybeSuccessfulRes !== undefined) {
var err = convertResponse(maybeSuccessfulRes);
if (err.TAG !== "Ok") {
return err;
}
if (maybeSuccessfulRes.nextBlock > toBlock) {
return err;
}
var datas = err._0;
var restRes = await queryBlockData(serverUrl, apiToken, maybeSuccessfulRes.nextBlock, toBlock, logger$1);
return Belt_Result.map(restRes, (function (rest) {
return Belt_Array.concat(datas, rest);
}));
}
var logger$2 = Logging.createChild({
url: serverUrl
});
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.");
await Time.resolvePromiseAfterDelay(100);
return await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger$2);
}
async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, logger) {
var firstBlock = Belt_Array.get(blockNumbers, 0);
if (firstBlock === undefined) {
return {
TAG: "Ok",
_0: []
};
}
var fromBlock = firstBlock;
var toBlock = firstBlock;
var set = new Set();
for(var idx = 0 ,idx_finish = blockNumbers.length; idx < idx_finish; ++idx){
var blockNumber = blockNumbers[idx];
if (blockNumber < fromBlock) {
fromBlock = blockNumber;
}
if (blockNumber > toBlock) {
toBlock = blockNumber;
}
set.add(blockNumber);
}
if ((toBlock - fromBlock | 0) > 1000) {
Js_exn.raiseError("Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: " + String(fromBlock) + "-" + String(toBlock));
}
var res = await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger);
var filtered = Belt_Result.map(res, (function (datas) {
return Belt_Array.keep(datas, (function (data) {
return set.delete(data.blockNumber);
}));
}));
if (set.size > 0) {
Js_exn.raiseError("Invalid response. Failed to get block data for block numbers: " + Array.from(set).join(", "));
}
return filtered;
}
function queryBlockData$1(serverUrl, apiToken, blockNumber, logger) {
return queryBlockData(serverUrl, apiToken, blockNumber, blockNumber, logger).then(function (res) {
return Belt_Result.map(res, (function (res) {
return Belt_Array.get(res, 0);
}));
});
}
var Log = {};
var GetLogs = {
$$Error: $$Error,
query: query
};
exports.Log = Log;
exports.queryErrorToMsq = queryErrorToMsq;
exports.GetLogs = GetLogs;
exports.queryBlockData = queryBlockData$1;
exports.queryBlockDataMulti = queryBlockDataMulti;
exports.mapExn = mapExn;
/* Rest Not a pure module */