UNPKG

envio

Version:

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

948 lines (904 loc) • 36.8 kB
// Generated by ReScript, PLEASE EDIT WITH CARE 'use strict'; var Caml = require("rescript/lib/js/caml.js"); var Utils = require("./Utils.res.js"); var Js_exn = require("rescript/lib/js/js_exn.js"); var Js_dict = require("rescript/lib/js/js_dict.js"); var Logging = require("./Logging.res.js"); var Belt_Int = require("rescript/lib/js/belt_Int.js"); var Caml_obj = require("rescript/lib/js/caml_obj.js"); var Belt_Array = require("rescript/lib/js/belt_Array.js"); var Prometheus = require("./Prometheus.res.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"); function copy(fetchState) { return { partitions: fetchState.partitions, nextPartitionIndex: fetchState.nextPartitionIndex, isFetchingAtHead: fetchState.isFetchingAtHead, endBlock: fetchState.endBlock, maxAddrInPartition: fetchState.maxAddrInPartition, firstEventBlockNumber: fetchState.firstEventBlockNumber, normalSelection: fetchState.normalSelection, indexingContracts: fetchState.indexingContracts, contractConfigs: fetchState.contractConfigs, dcsToStore: fetchState.dcsToStore, chainId: fetchState.chainId, latestFullyFetchedBlock: fetchState.latestFullyFetchedBlock, blockLag: fetchState.blockLag, queue: fetchState.queue.slice(0) }; } function eventItemGt(a, b) { if (a.blockNumber > b.blockNumber) { return true; } else if (a.blockNumber === b.blockNumber) { return a.logIndex > b.logIndex; } else { return false; } } function mergeSortedEventList(a, b) { return Utils.$$Array.mergeSorted(eventItemGt, a, b); } function mergeIntoPartition(p, target, maxAddrInPartition) { if (!p.selection.dependsOnAddresses) { return [ p, target ]; } if (!target.selection.dependsOnAddresses) { return [ p, target ]; } var latestFetchedBlock = target.latestFetchedBlock; var mergedAddresses = {}; var allowedAddressesNumber = { contents: maxAddrInPartition }; Utils.Dict.forEachWithKey(target.addressesByContractName, (function (contractName, addresses) { allowedAddressesNumber.contents = allowedAddressesNumber.contents - addresses.length | 0; mergedAddresses[contractName] = addresses; })); Utils.Dict.forEachWithKey(p.addressesByContractName, (function (contractName, addresses) { allowedAddressesNumber.contents = allowedAddressesNumber.contents - addresses.length | 0; var targetAddresses = mergedAddresses[contractName]; if (targetAddresses !== undefined) { mergedAddresses[contractName] = Belt_Array.concat(targetAddresses, addresses); } else { mergedAddresses[contractName] = addresses; } })); var rest; if (allowedAddressesNumber.contents < 0) { var restAddresses = {}; Utils.Dict.forEachWithKey(mergedAddresses, (function (contractName, addresses) { if (allowedAddressesNumber.contents === 0) { return ; } if (addresses.length <= (-allowedAddressesNumber.contents | 0)) { allowedAddressesNumber.contents = allowedAddressesNumber.contents + addresses.length | 0; Utils.Dict.deleteInPlace(mergedAddresses, contractName); restAddresses[contractName] = addresses; return ; } var restFrom = addresses.length + allowedAddressesNumber.contents | 0; mergedAddresses[contractName] = addresses.slice(0, restFrom); restAddresses[contractName] = addresses.slice(restFrom); allowedAddressesNumber.contents = 0; })); rest = { id: p.id, status: { fetchingStateId: undefined }, latestFetchedBlock: latestFetchedBlock, selection: target.selection, addressesByContractName: restAddresses }; } else { rest = undefined; } return [ { id: target.id, status: { fetchingStateId: undefined }, latestFetchedBlock: latestFetchedBlock, selection: target.selection, addressesByContractName: mergedAddresses }, rest ]; } function checkIsWithinSyncRange(latestFetchedBlock, currentBlockHeight) { return (currentBlockHeight - latestFetchedBlock.blockNumber) / currentBlockHeight <= 0.001; } function updateInternal(fetchState, partitionsOpt, nextPartitionIndexOpt, indexingContractsOpt, dcsToStoreOpt, currentBlockHeight, queueOpt) { var partitions = partitionsOpt !== undefined ? partitionsOpt : fetchState.partitions; var nextPartitionIndex = nextPartitionIndexOpt !== undefined ? nextPartitionIndexOpt : fetchState.nextPartitionIndex; var indexingContracts = indexingContractsOpt !== undefined ? indexingContractsOpt : fetchState.indexingContracts; var dcsToStore = dcsToStoreOpt !== undefined ? Caml_option.valFromOption(dcsToStoreOpt) : fetchState.dcsToStore; var queue = queueOpt !== undefined ? queueOpt : fetchState.queue; var firstPartition = partitions[0]; var latestFullyFetchedBlock = firstPartition.latestFetchedBlock; for(var idx = 0 ,idx_finish = partitions.length; idx < idx_finish; ++idx){ var p = partitions[idx]; if (latestFullyFetchedBlock.blockNumber > p.latestFetchedBlock.blockNumber) { latestFullyFetchedBlock = p.latestFetchedBlock; } } var latestFullyFetchedBlock$1 = latestFullyFetchedBlock; var isFetchingAtHead = currentBlockHeight !== undefined ? ( latestFullyFetchedBlock$1.blockNumber >= currentBlockHeight ? true : fetchState.isFetchingAtHead && checkIsWithinSyncRange(latestFullyFetchedBlock$1, currentBlockHeight) ) : fetchState.isFetchingAtHead; var queueSize = queue.length; Prometheus.IndexingPartitions.set(partitions.length, fetchState.chainId); Prometheus.IndexingBufferSize.set(queueSize, fetchState.chainId); Prometheus.IndexingBufferBlockNumber.set(latestFullyFetchedBlock$1.blockNumber, fetchState.chainId); var item = Utils.$$Array.last(queue); return { partitions: partitions, nextPartitionIndex: nextPartitionIndex, isFetchingAtHead: isFetchingAtHead, endBlock: fetchState.endBlock, maxAddrInPartition: fetchState.maxAddrInPartition, firstEventBlockNumber: item !== undefined ? Utils.$$Math.minOptInt(fetchState.firstEventBlockNumber, item.blockNumber) : fetchState.firstEventBlockNumber, normalSelection: fetchState.normalSelection, indexingContracts: indexingContracts, contractConfigs: fetchState.contractConfigs, dcsToStore: dcsToStore, chainId: fetchState.chainId, latestFullyFetchedBlock: latestFullyFetchedBlock$1, blockLag: fetchState.blockLag, queue: queue }; } function numAddresses(fetchState) { return Object.keys(fetchState.indexingContracts).length; } function warnDifferentContractType(fetchState, existingContract, dc) { var logger = Logging.createChild({ chainId: fetchState.chainId, contractAddress: dc.address, existingContractType: existingContract.contractName, newContractType: dc.contractName }); Logging.childWarn(logger, "Skipping contract registration: Contract address is already registered for one contract and cannot be registered for another contract."); } function registerDynamicContracts(fetchState, dynamicContracts, currentBlockHeight) { if (Utils.$$Array.isEmpty(fetchState.normalSelection.eventConfigs)) { Js_exn.raiseError("Invalid configuration. No events to fetch for the dynamic contract registration."); } var indexingContracts = fetchState.indexingContracts; var registeringContracts = {}; var addressesByContractName = {}; var earliestRegisteringEventBlockNumber = Infinity; var hasDCWithFilterByAddresses = false; for(var idx = 0 ,idx_finish = dynamicContracts.length; idx < idx_finish; ++idx){ var dc = dynamicContracts[idx]; var match = fetchState.contractConfigs[dc.contractName]; if (match !== undefined) { var existingContract = indexingContracts[dc.address]; if (existingContract !== undefined) { if (existingContract.contractName !== dc.contractName) { warnDifferentContractType(fetchState, existingContract, dc); } else if (existingContract.startBlock > dc.startBlock) { var logger = Logging.createChild({ chainId: fetchState.chainId, contractAddress: dc.address, existingBlockNumber: existingContract.startBlock, newBlockNumber: dc.startBlock }); Logging.childWarn(logger, "Skipping contract registration: Contract address is already registered at a later block number. Currently registration of the same contract address is not supported by Envio. Reach out to us if it's a problem for you."); } } else { var registeringContract = registeringContracts[dc.address]; var shouldUpdate; if (registeringContract !== undefined) { if (registeringContract.contractName !== dc.contractName) { warnDifferentContractType(fetchState, registeringContract, dc); shouldUpdate = false; } else { var match$1 = registeringContract.register; var match$2 = dc.register; shouldUpdate = typeof match$1 !== "object" || typeof match$2 !== "object" ? Js_exn.raiseError("Unexpected case: Config registration should be handled in a different function") : registeringContract.startBlock > dc.startBlock || registeringContract.startBlock === dc.startBlock && match$1.registeringEventLogIndex > match$2.registeringEventLogIndex; } } else { hasDCWithFilterByAddresses = hasDCWithFilterByAddresses || match.filterByAddresses; Utils.Dict.push(addressesByContractName, dc.contractName, dc.address); shouldUpdate = true; } if (shouldUpdate) { earliestRegisteringEventBlockNumber = earliestRegisteringEventBlockNumber < dc.startBlock ? earliestRegisteringEventBlockNumber : dc.startBlock; registeringContracts[dc.address] = dc; } } } else { var logger$1 = Logging.createChild({ chainId: fetchState.chainId, contractAddress: dc.address, contractName: dc.contractName }); Logging.childWarn(logger$1, "Skipping contract registration: Contract doesn't have any events to fetch."); } } var dcsToStore = Js_dict.values(registeringContracts); if (dcsToStore.length === 0) { return fetchState; } var newPartitions; if (dcsToStore.length <= fetchState.maxAddrInPartition && !hasDCWithFilterByAddresses) { newPartitions = [{ id: String(fetchState.nextPartitionIndex), status: { fetchingStateId: undefined }, latestFetchedBlock: { blockNumber: earliestRegisteringEventBlockNumber - 1 | 0, blockTimestamp: 0 }, selection: fetchState.normalSelection, addressesByContractName: addressesByContractName }]; } else { var partitions = []; var earliestRegisteringEventBlockNumber$1 = { contents: Infinity }; var pendingAddressesByContractName = { contents: {} }; var pendingCount = 0; var addPartition = function () { partitions.push({ id: String(fetchState.nextPartitionIndex + partitions.length | 0), status: { fetchingStateId: undefined }, latestFetchedBlock: { blockNumber: earliestRegisteringEventBlockNumber$1.contents - 1 | 0, blockTimestamp: 0 }, selection: fetchState.normalSelection, addressesByContractName: pendingAddressesByContractName.contents }); }; for(var idx$1 = 0 ,idx_finish$1 = Object.keys(addressesByContractName).length; idx$1 < idx_finish$1; ++idx$1){ var contractName = Object.keys(addressesByContractName)[idx$1]; var addresses = addressesByContractName[contractName]; var contractConfig = fetchState.contractConfigs[contractName]; if (contractConfig.filterByAddresses) { var byStartBlock = {}; for(var jdx = 0 ,jdx_finish = addresses.length; jdx < jdx_finish; ++jdx){ var address = addresses[jdx]; var indexingContract = registeringContracts[address]; Utils.Dict.push(byStartBlock, String(indexingContract.startBlock), address); } Object.keys(byStartBlock).forEach((function(contractName,byStartBlock){ return function (startBlockKey) { var addresses = byStartBlock[startBlockKey]; var addressesByContractName = {}; addressesByContractName[contractName] = addresses; partitions.push({ id: String(fetchState.nextPartitionIndex + partitions.length | 0), status: { fetchingStateId: undefined }, latestFetchedBlock: { blockNumber: Caml.int_max(Belt_Option.getExn(Belt_Int.fromString(startBlockKey)) - 1 | 0, 0), blockTimestamp: 0 }, selection: fetchState.normalSelection, addressesByContractName: addressesByContractName }); } }(contractName,byStartBlock))); } else { for(var jdx$1 = 0 ,jdx_finish$1 = addresses.length; jdx$1 < jdx_finish$1; ++jdx$1){ var address$1 = addresses[jdx$1]; if (pendingCount === fetchState.maxAddrInPartition) { addPartition(); pendingAddressesByContractName.contents = {}; pendingCount = 0; earliestRegisteringEventBlockNumber$1.contents = Infinity; } var indexingContract$1 = registeringContracts[address$1]; pendingCount = pendingCount + 1 | 0; Utils.Dict.push(pendingAddressesByContractName.contents, contractName, address$1); earliestRegisteringEventBlockNumber$1.contents = earliestRegisteringEventBlockNumber$1.contents < indexingContract$1.startBlock ? earliestRegisteringEventBlockNumber$1.contents : indexingContract$1.startBlock; } } } if (pendingCount > 0) { addPartition(); } newPartitions = partitions; } Prometheus.IndexingAddresses.set(Object.keys(fetchState.indexingContracts).length + dcsToStore.length | 0, fetchState.chainId); var existingDcs = fetchState.dcsToStore; return updateInternal(fetchState, fetchState.partitions.concat(newPartitions), fetchState.nextPartitionIndex + newPartitions.length | 0, Object.assign(registeringContracts, indexingContracts), Caml_option.some(existingDcs !== undefined ? Belt_Array.concat(existingDcs, dcsToStore) : dcsToStore), currentBlockHeight, undefined); } var UnexpectedPartitionNotFound = /* @__PURE__ */Caml_exceptions.create("FetchState.UnexpectedPartitionNotFound"); var UnexpectedMergeQueryResponse = /* @__PURE__ */Caml_exceptions.create("FetchState.UnexpectedMergeQueryResponse"); function handleQueryResult(fetchState, query, latestFetchedBlock, reversedNewItems, currentBlockHeight) { var partitions = fetchState.partitions; var partitionId = query.partitionId; var pIndex = Belt_Array.getIndexBy(partitions, (function (p) { return p.id === partitionId; })); var tmp; if (pIndex !== undefined) { var p = partitions[pIndex]; var updatedPartition_id = p.id; var updatedPartition_status = { fetchingStateId: undefined }; var updatedPartition_selection = p.selection; var updatedPartition_addressesByContractName = p.addressesByContractName; var updatedPartition = { id: updatedPartition_id, status: updatedPartition_status, latestFetchedBlock: latestFetchedBlock, selection: updatedPartition_selection, addressesByContractName: updatedPartition_addressesByContractName }; var match = query.target; var exit = 0; if (typeof match !== "object" || match.TAG === "EndBlock") { exit = 1; } else { var intoPartitionId = match.intoPartitionId; var targetIndex = Belt_Array.getIndexBy(partitions, (function (p) { return p.id === intoPartitionId; })); var exit$1 = 0; if (targetIndex !== undefined && partitions[targetIndex].latestFetchedBlock.blockNumber === latestFetchedBlock.blockNumber) { var target = partitions[targetIndex]; var match$1 = mergeIntoPartition(updatedPartition, target, fetchState.maxAddrInPartition); var rest = match$1[1]; var updatedPartitions = Utils.$$Array.setIndexImmutable(partitions, targetIndex, match$1[0]); var updatedPartitions$1 = rest !== undefined ? (updatedPartitions[pIndex] = rest, updatedPartitions) : Utils.$$Array.removeAtIndex(updatedPartitions, pIndex); tmp = { TAG: "Ok", _0: updatedPartitions$1 }; } else { exit$1 = 2; } if (exit$1 === 2) { tmp = { TAG: "Ok", _0: Utils.$$Array.setIndexImmutable(partitions, pIndex, updatedPartition) }; } } if (exit === 1) { tmp = { TAG: "Ok", _0: Utils.$$Array.setIndexImmutable(partitions, pIndex, updatedPartition) }; } } else { tmp = { TAG: "Error", _0: { RE_EXN_ID: UnexpectedPartitionNotFound, partitionId: partitionId } }; } return Belt_Result.map(tmp, (function (partitions) { return updateInternal(fetchState, partitions, undefined, undefined, undefined, currentBlockHeight, mergeSortedEventList(reversedNewItems, fetchState.queue)); })); } function makePartitionQuery(p, indexingContracts, endBlock, mergeTarget) { var latestFetchedBlockNumber = p.latestFetchedBlock.blockNumber; var fromBlock = latestFetchedBlockNumber !== 0 ? latestFetchedBlockNumber + 1 | 0 : 0; var tmp; var exit = 0; if (endBlock !== undefined) { if (fromBlock > endBlock) { tmp = undefined; } else if (mergeTarget !== undefined) { exit = 1; } else { tmp = { TAG: "EndBlock", toBlock: endBlock }; } } else if (mergeTarget !== undefined) { exit = 1; } else { tmp = "Head"; } if (exit === 1) { tmp = { TAG: "Merge", intoPartitionId: mergeTarget.id, toBlock: mergeTarget.latestFetchedBlock.blockNumber }; } return Belt_Option.map(tmp, (function (target) { return { partitionId: p.id, fromBlock: fromBlock, selection: p.selection, addressesByContractName: p.addressesByContractName, target: target, indexingContracts: indexingContracts }; })); } function startFetchingQueries(param, queries, stateId) { var partitions = param.partitions; Belt_Array.forEach(queries, (function (q) { var p = partitions.find(function (p) { return p.id === q.partitionId; }); if (p !== undefined) { p.status.fetchingStateId = stateId; return ; } else { return Js_exn.raiseError("Unexpected case: Couldn't find partition for the fetching query"); } })); } function addressesByContractNameCount(addressesByContractName) { var numAddresses = 0; var contractNames = Object.keys(addressesByContractName); for(var idx = 0 ,idx_finish = contractNames.length; idx < idx_finish; ++idx){ var contractName = contractNames[idx]; numAddresses = numAddresses + addressesByContractName[contractName].length | 0; } return numAddresses; } function addressesByContractNameGetAll(addressesByContractName) { var all = []; var contractNames = Object.keys(addressesByContractName); for(var idx = 0 ,idx_finish = contractNames.length; idx < idx_finish; ++idx){ var contractName = contractNames[idx]; all = Belt_Array.concat(all, addressesByContractName[contractName]); } return all; } function isFullPartition(p, maxAddrInPartition) { if (p.selection.dependsOnAddresses) { return addressesByContractNameCount(p.addressesByContractName) >= maxAddrInPartition; } else { return true; } } function getNextQuery(param, concurrencyLimit, targetBufferSize, currentBlockHeight, stateId) { if (currentBlockHeight === 0) { return "WaitingForNewBlock"; } if (concurrencyLimit === 0) { return "ReachedMaxConcurrency"; } var queue = param.queue; var blockLag = param.blockLag; var indexingContracts = param.indexingContracts; var maxAddrInPartition = param.maxAddrInPartition; var endBlock = param.endBlock; var partitions = param.partitions; var headBlock = currentBlockHeight - Belt_Option.getWithDefault(blockLag, 0) | 0; var fullPartitions = []; var mergingPartitions = []; var areMergingPartitionsFetching = false; var mostBehindMergingPartition; var mergingPartitionTarget; var shouldWaitForNewBlock = endBlock !== undefined ? headBlock < endBlock : true; var checkIsFetchingPartition = function (p) { var fetchingStateId = p.status.fetchingStateId; if (fetchingStateId !== undefined) { return stateId <= fetchingStateId; } else { return false; } }; for(var idx = 0 ,idx_finish = partitions.length; idx < idx_finish; ++idx){ var p = partitions[idx]; var isFetching = checkIsFetchingPartition(p); var hasReachedTheHead = p.latestFetchedBlock.blockNumber >= headBlock; if (isFetching || !hasReachedTheHead) { shouldWaitForNewBlock = false; } if (p.selection.dependsOnAddresses ? addressesByContractNameCount(p.addressesByContractName) >= maxAddrInPartition : true) { fullPartitions.push(p); } else { mergingPartitions.push(p); var mostBehindMergingPartition$1 = mostBehindMergingPartition; var tmp; if (mostBehindMergingPartition$1 !== undefined) { if (mostBehindMergingPartition$1.latestFetchedBlock.blockNumber === p.latestFetchedBlock.blockNumber) { tmp = mostBehindMergingPartition$1; } else if (mostBehindMergingPartition$1.latestFetchedBlock.blockNumber < p.latestFetchedBlock.blockNumber) { var mergingPartitionTarget$1 = mergingPartitionTarget; mergingPartitionTarget = mergingPartitionTarget$1 !== undefined && mergingPartitionTarget$1.latestFetchedBlock.blockNumber < p.latestFetchedBlock.blockNumber ? mergingPartitionTarget$1 : p; tmp = mostBehindMergingPartition$1; } else { mergingPartitionTarget = mostBehindMergingPartition$1; tmp = p; } } else { tmp = p; } mostBehindMergingPartition = tmp; if (isFetching) { areMergingPartitionsFetching = true; } } } var targetBlockIdx = queue.length - targetBufferSize | 0; var maxQueryBlockNumber; if (targetBlockIdx < 0) { maxQueryBlockNumber = currentBlockHeight; } else { var item = Belt_Array.get(queue, targetBlockIdx); maxQueryBlockNumber = item !== undefined && item.blockNumber < currentBlockHeight ? item.blockNumber : currentBlockHeight; } var queries = []; var registerPartitionQuery = function (p, mergeTarget) { if (!(!checkIsFetchingPartition(p) && p.latestFetchedBlock.blockNumber < maxQueryBlockNumber)) { return ; } var q = makePartitionQuery(p, indexingContracts, blockLag !== undefined ? ( endBlock !== undefined ? ( headBlock < endBlock ? headBlock : endBlock ) : headBlock ) : endBlock, mergeTarget); if (q !== undefined) { queries.push(q); return ; } }; Belt_Array.forEach(fullPartitions, (function (p) { registerPartitionQuery(p, undefined); })); if (!areMergingPartitionsFetching) { var len = mergingPartitions.length; if (len !== 1) { if (len !== 0) { var match = mostBehindMergingPartition; var match$1 = mergingPartitionTarget; if (match !== undefined) { if (match$1 !== undefined) { registerPartitionQuery(match, match$1); } else { registerPartitionQuery(match, undefined); } } else { Js_exn.raiseError("Unexpected case, should always have a most behind partition."); } } } else { var p$1 = mergingPartitions[0]; registerPartitionQuery(p$1, undefined); } } if (Utils.$$Array.isEmpty(queries)) { if (shouldWaitForNewBlock) { return "WaitingForNewBlock"; } else { return "NothingToQuery"; } } else { return { TAG: "Ready", _0: queries.length > concurrencyLimit ? queries.sort(function (a, b) { return a.fromBlock - b.fromBlock | 0; }).slice(0, concurrencyLimit) : queries }; } } function queueItemBlockNumber(queueItem) { if (queueItem.TAG === "Item") { return queueItem._0.item.blockNumber; } var blockNumber = queueItem.latestFetchedBlock.blockNumber; if (blockNumber === 0) { return 0; } else { return blockNumber + 1 | 0; } } function queueItemIsInReorgThreshold(queueItem, currentBlockHeight, highestBlockBelowThreshold) { if (currentBlockHeight === 0) { return false; } else { return queueItemBlockNumber(queueItem) > highestBlockBelowThreshold; } } function makeNoItem(param) { return { TAG: "NoItem", latestFetchedBlock: param.latestFetchedBlock }; } function qItemLt(a, b) { var aBlockNumber = queueItemBlockNumber(a); var bBlockNumber = queueItemBlockNumber(b); if (aBlockNumber < bBlockNumber) { return true; } else if (aBlockNumber === bBlockNumber) { if (a.TAG === "Item") { if (b.TAG === "Item") { return a._0.item.logIndex < b._0.item.logIndex; } else { return false; } } else if (b.TAG === "Item") { return true; } else { return false; } } else { return false; } } function getEarliestEvent(param) { var queue = param.queue; var latestFullyFetchedBlock = param.latestFullyFetchedBlock; var item = Utils.$$Array.last(queue); if (item !== undefined && item.blockNumber <= latestFullyFetchedBlock.blockNumber) { return { TAG: "Item", _0: { item: item, popItemOffQueue: (function () { queue.pop(); }) } }; } else { return { TAG: "NoItem", latestFetchedBlock: latestFullyFetchedBlock }; } } function make(startBlock, endBlock, eventConfigs, contracts, maxAddrInPartition, chainId, blockLag) { var latestFetchedBlock_blockNumber = startBlock - 1 | 0; var latestFetchedBlock = { blockNumber: latestFetchedBlock_blockNumber, blockTimestamp: 0 }; var notDependingOnAddresses = []; var normalEventConfigs = []; var contractNamesWithNormalEvents = new Set(); var indexingContracts = {}; var contractConfigs = {}; Belt_Array.forEach(eventConfigs, (function (ec) { var match = contractConfigs[ec.contractName]; if (match !== undefined) { contractConfigs[ec.contractName] = { filterByAddresses: match.filterByAddresses || ec.filterByAddresses }; } else { contractConfigs[ec.contractName] = { filterByAddresses: ec.filterByAddresses }; } if (ec.dependsOnAddresses) { normalEventConfigs.push(ec); contractNamesWithNormalEvents.add(ec.contractName); } else { notDependingOnAddresses.push(ec); } })); var partitions = []; if (notDependingOnAddresses.length !== 0) { partitions.push({ id: String(partitions.length), status: { fetchingStateId: undefined }, latestFetchedBlock: latestFetchedBlock, selection: { eventConfigs: notDependingOnAddresses, dependsOnAddresses: false }, addressesByContractName: {} }); } var normalSelection = { eventConfigs: normalEventConfigs, dependsOnAddresses: true }; if (normalEventConfigs.length !== 0) { var makePendingNormalPartition = function () { return { id: String(partitions.length), status: { fetchingStateId: undefined }, latestFetchedBlock: latestFetchedBlock, selection: normalSelection, addressesByContractName: {} }; }; var pendingNormalPartition = { contents: makePendingNormalPartition() }; Belt_Array.forEach(contracts, (function (contract) { var contractName = contract.contractName; if (!contractNamesWithNormalEvents.has(contractName)) { return ; } var pendingPartition = pendingNormalPartition.contents; Utils.Dict.push(pendingPartition.addressesByContractName, contractName, contract.address); indexingContracts[contract.address] = contract; if (addressesByContractNameCount(pendingPartition.addressesByContractName) === maxAddrInPartition) { partitions.push(pendingPartition); pendingNormalPartition.contents = makePendingNormalPartition(); return ; } })); if (addressesByContractNameCount(pendingNormalPartition.contents.addressesByContractName) > 0) { partitions.push(pendingNormalPartition.contents); } } if (partitions.length === 0) { Js_exn.raiseError("Invalid configuration: Nothing to fetch. Make sure that you provided at least one contract address to index, or have events with Wildcard mode enabled."); } var numAddresses = Object.keys(indexingContracts).length; Prometheus.IndexingAddresses.set(numAddresses, chainId); Prometheus.IndexingPartitions.set(partitions.length, chainId); Prometheus.IndexingBufferSize.set(0, chainId); Prometheus.IndexingBufferBlockNumber.set(latestFetchedBlock_blockNumber, chainId); if (endBlock !== undefined) { Prometheus.IndexingEndBlock.set(endBlock, chainId); } return { partitions: partitions, nextPartitionIndex: partitions.length, isFetchingAtHead: false, endBlock: endBlock, maxAddrInPartition: maxAddrInPartition, firstEventBlockNumber: undefined, normalSelection: normalSelection, indexingContracts: indexingContracts, contractConfigs: contractConfigs, dcsToStore: undefined, chainId: chainId, latestFullyFetchedBlock: latestFetchedBlock, blockLag: blockLag, queue: [] }; } function queueSize(param) { return param.queue.length; } function getLatestFullyFetchedBlock(param) { return param.latestFullyFetchedBlock; } function pruneQueueFromFirstChangeEvent(queue, firstChangeEvent) { return Belt_Array.keep(queue, (function (item) { return Caml_obj.lessthan([ item.blockNumber, item.logIndex ], [ firstChangeEvent.blockNumber, firstChangeEvent.logIndex ]); })); } function rollbackPartition(p, firstChangeEvent, addressesToRemove) { if (!p.selection.dependsOnAddresses) { return { id: p.id, status: { fetchingStateId: undefined }, latestFetchedBlock: p.latestFetchedBlock, selection: p.selection, addressesByContractName: p.addressesByContractName }; } var rollbackedAddressesByContractName = {}; Utils.Dict.forEachWithKey(p.addressesByContractName, (function (contractName, addresses) { var keptAddresses = Belt_Array.keep(addresses, (function (address) { return !addressesToRemove.has(address); })); if (keptAddresses.length !== 0) { rollbackedAddressesByContractName[contractName] = keptAddresses; return ; } })); if (Object.keys(rollbackedAddressesByContractName).length === 0) { return ; } var shouldRollbackFetched = p.latestFetchedBlock.blockNumber >= firstChangeEvent.blockNumber; return { id: p.id, status: { fetchingStateId: undefined }, latestFetchedBlock: shouldRollbackFetched ? ({ blockNumber: firstChangeEvent.blockNumber - 1 | 0, blockTimestamp: 0 }) : p.latestFetchedBlock, selection: p.selection, addressesByContractName: rollbackedAddressesByContractName }; } function rollback(fetchState, firstChangeEvent) { var addressesToRemove = new Set(); var indexingContracts = {}; Belt_Array.forEach(Object.keys(fetchState.indexingContracts), (function (address) { var indexingContract = fetchState.indexingContracts[address]; var dc = indexingContract.register; var tmp; tmp = typeof dc !== "object" ? true : indexingContract.startBlock < firstChangeEvent.blockNumber || indexingContract.startBlock === firstChangeEvent.blockNumber && dc.registeringEventLogIndex < firstChangeEvent.logIndex; if (tmp) { indexingContracts[address] = indexingContract; } else { addressesToRemove.add(address); } })); var partitions = Belt_Array.keepMap(fetchState.partitions, (function (p) { return rollbackPartition(p, firstChangeEvent, addressesToRemove); })); var dcsToStore = fetchState.dcsToStore; var tmp; if (dcsToStore !== undefined) { var filtered = dcsToStore.filter(function (dc) { return !addressesToRemove.has(dc.address); }); tmp = filtered.length !== 0 ? filtered : undefined; } else { tmp = undefined; } return updateInternal(fetchState, partitions, undefined, indexingContracts, Caml_option.some(tmp), undefined, pruneQueueFromFirstChangeEvent(fetchState.queue, firstChangeEvent)); } function isActivelyIndexing(fetchState) { var endBlock = fetchState.endBlock; if (endBlock === undefined) { return true; } var isPastEndblock = fetchState.latestFullyFetchedBlock.blockNumber >= endBlock; if (isPastEndblock) { return queueSize(fetchState) > 0; } else { return true; } } exports.copy = copy; exports.eventItemGt = eventItemGt; exports.mergeSortedEventList = mergeSortedEventList; exports.mergeIntoPartition = mergeIntoPartition; exports.checkIsWithinSyncRange = checkIsWithinSyncRange; exports.updateInternal = updateInternal; exports.numAddresses = numAddresses; exports.warnDifferentContractType = warnDifferentContractType; exports.registerDynamicContracts = registerDynamicContracts; exports.UnexpectedPartitionNotFound = UnexpectedPartitionNotFound; exports.UnexpectedMergeQueryResponse = UnexpectedMergeQueryResponse; exports.handleQueryResult = handleQueryResult; exports.makePartitionQuery = makePartitionQuery; exports.startFetchingQueries = startFetchingQueries; exports.addressesByContractNameCount = addressesByContractNameCount; exports.addressesByContractNameGetAll = addressesByContractNameGetAll; exports.isFullPartition = isFullPartition; exports.getNextQuery = getNextQuery; exports.queueItemBlockNumber = queueItemBlockNumber; exports.queueItemIsInReorgThreshold = queueItemIsInReorgThreshold; exports.makeNoItem = makeNoItem; exports.qItemLt = qItemLt; exports.getEarliestEvent = getEarliestEvent; exports.make = make; exports.queueSize = queueSize; exports.getLatestFullyFetchedBlock = getLatestFullyFetchedBlock; exports.pruneQueueFromFirstChangeEvent = pruneQueueFromFirstChangeEvent; exports.rollbackPartition = rollbackPartition; exports.rollback = rollback; exports.isActivelyIndexing = isActivelyIndexing; /* Utils Not a pure module */