envio
Version:
A latency and sync speed optimized, developer friendly blockchain data indexer.
948 lines (904 loc) • 36.8 kB
JavaScript
// Generated by ReScript, PLEASE EDIT WITH CARE
;
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 */