UNPKG

envio

Version:

A latency and sync speed optimized, developer friendly blockchain data indexer.

335 lines (313 loc) • 13.4 kB
// Generated by ReScript, PLEASE EDIT WITH CARE 'use strict'; 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 */