envio
Version:
A latency and sync speed optimized, developer friendly blockchain data indexer.
1,124 lines (1,074 loc) • 45.4 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 Js_math = require("rescript/lib/js/js_math.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 Caml_int32 = require("rescript/lib/js/caml_int32.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,
startBlock: fetchState.startBlock,
endBlock: fetchState.endBlock,
maxAddrInPartition: fetchState.maxAddrInPartition,
normalSelection: fetchState.normalSelection,
indexingContracts: fetchState.indexingContracts,
contractConfigs: fetchState.contractConfigs,
dcsToStore: fetchState.dcsToStore,
chainId: fetchState.chainId,
latestFullyFetchedBlock: fetchState.latestFullyFetchedBlock,
latestOnBlockBlockNumber: fetchState.latestOnBlockBlockNumber,
blockLag: fetchState.blockLag,
queue: fetchState.queue.slice(0),
targetBufferSize: fetchState.targetBufferSize,
onBlockConfigs: fetchState.onBlockConfigs
};
}
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 bufferBlockNumber(param) {
var latestOnBlockBlockNumber = param.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = param.latestFullyFetchedBlock;
if (latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber) {
return latestOnBlockBlockNumber;
} else {
return latestFullyFetchedBlock.blockNumber;
}
}
function bufferBlock(param) {
var latestOnBlockBlockNumber = param.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = param.latestFullyFetchedBlock;
if (latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber) {
return {
blockNumber: latestOnBlockBlockNumber,
blockTimestamp: 0
};
} else {
return latestFullyFetchedBlock;
}
}
function compareBufferItem(a, b) {
var blockDiff = b.blockNumber - a.blockNumber | 0;
if (blockDiff === 0) {
return b.logIndex - a.logIndex | 0;
} else {
return blockDiff;
}
}
function updateInternal(fetchState, partitionsOpt, nextPartitionIndexOpt, indexingContractsOpt, dcsToStoreOpt, mutItems, blockLagOpt) {
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 blockLag = blockLagOpt !== undefined ? blockLagOpt : fetchState.blockLag;
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 mutItemsRef = mutItems;
var onBlockConfigs = fetchState.onBlockConfigs;
var latestOnBlockBlockNumber;
if (onBlockConfigs.length !== 0) {
var mutItems$1 = mutItemsRef;
var item = (
mutItems$1 !== undefined ? mutItems$1 : fetchState.queue
).at(-fetchState.targetBufferSize | 0);
var maxBlockNumber = item !== undefined ? item.blockNumber : latestFullyFetchedBlock$1.blockNumber;
var mutItems$2 = mutItemsRef;
var mutItems$3 = mutItems$2 !== undefined ? mutItems$2 : fetchState.queue.slice(0);
mutItemsRef = mutItems$3;
var newItemsCounter = 0;
var latestOnBlockBlockNumber$1 = fetchState.latestOnBlockBlockNumber;
while(latestOnBlockBlockNumber$1 < maxBlockNumber && newItemsCounter <= fetchState.targetBufferSize) {
var blockNumber = latestOnBlockBlockNumber$1 + 1 | 0;
latestOnBlockBlockNumber$1 = blockNumber;
for(var configIdx = 0 ,configIdx_finish = onBlockConfigs.length; configIdx < configIdx_finish; ++configIdx){
var onBlockConfig = onBlockConfigs[configIdx];
var startBlock = onBlockConfig.startBlock;
var handlerStartBlock = startBlock !== undefined ? startBlock : fetchState.startBlock;
var tmp = false;
if (blockNumber >= handlerStartBlock) {
var endBlock = onBlockConfig.endBlock;
tmp = endBlock !== undefined ? blockNumber <= endBlock : true;
}
if (tmp && Caml_int32.mod_(blockNumber - handlerStartBlock | 0, onBlockConfig.interval) === 0) {
mutItems$3.push({
kind: 1,
onBlockConfig: onBlockConfig,
blockNumber: blockNumber,
logIndex: 16777216 + onBlockConfig.index | 0
});
newItemsCounter = newItemsCounter + 1 | 0;
}
}
};
latestOnBlockBlockNumber = latestOnBlockBlockNumber$1;
} else {
latestOnBlockBlockNumber = latestFullyFetchedBlock$1.blockNumber;
}
var mutItems$4 = mutItemsRef;
var updatedFetchState_startBlock = fetchState.startBlock;
var updatedFetchState_endBlock = fetchState.endBlock;
var updatedFetchState_maxAddrInPartition = fetchState.maxAddrInPartition;
var updatedFetchState_normalSelection = fetchState.normalSelection;
var updatedFetchState_contractConfigs = fetchState.contractConfigs;
var updatedFetchState_chainId = fetchState.chainId;
var updatedFetchState_queue = mutItems$4 !== undefined ? mutItems$4.sort(compareBufferItem) : fetchState.queue;
var updatedFetchState_targetBufferSize = fetchState.targetBufferSize;
var updatedFetchState_onBlockConfigs = fetchState.onBlockConfigs;
var updatedFetchState = {
partitions: partitions,
nextPartitionIndex: nextPartitionIndex,
startBlock: updatedFetchState_startBlock,
endBlock: updatedFetchState_endBlock,
maxAddrInPartition: updatedFetchState_maxAddrInPartition,
normalSelection: updatedFetchState_normalSelection,
indexingContracts: indexingContracts,
contractConfigs: updatedFetchState_contractConfigs,
dcsToStore: dcsToStore,
chainId: updatedFetchState_chainId,
latestFullyFetchedBlock: latestFullyFetchedBlock$1,
latestOnBlockBlockNumber: latestOnBlockBlockNumber,
blockLag: blockLag,
queue: updatedFetchState_queue,
targetBufferSize: updatedFetchState_targetBufferSize,
onBlockConfigs: updatedFetchState_onBlockConfigs
};
Prometheus.IndexingPartitions.set(partitions.length, fetchState.chainId);
Prometheus.IndexingBufferSize.set(updatedFetchState_queue.length, fetchState.chainId);
Prometheus.IndexingBufferBlockNumber.set(latestOnBlockBlockNumber < latestFullyFetchedBlock$1.blockNumber ? latestOnBlockBlockNumber : latestFullyFetchedBlock$1.blockNumber, fetchState.chainId);
return updatedFetchState;
}
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) {
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), undefined, undefined);
}
var UnexpectedPartitionNotFound = /* @__PURE__ */Caml_exceptions.create("FetchState.UnexpectedPartitionNotFound");
var UnexpectedMergeQueryResponse = /* @__PURE__ */Caml_exceptions.create("FetchState.UnexpectedMergeQueryResponse");
function handleQueryResult(fetchState, query, latestFetchedBlock, newItems) {
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, newItems.length !== 0 ? Belt_Array.concat(fetchState.queue, newItems) : undefined, undefined);
}));
}
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, currentBlockHeight, stateId) {
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 - blockLag | 0;
if (headBlock <= 0) {
return "WaitingForNewBlock";
}
if (concurrencyLimit === 0) {
return "ReachedMaxConcurrency";
}
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 - param.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 endBlock$1 = blockLag !== 0 ? (
endBlock !== undefined ? (
headBlock < endBlock ? headBlock : endBlock
) : headBlock
) : endBlock;
var match = maxQueryBlockNumber < currentBlockHeight;
var endBlock$2 = endBlock$1 !== undefined ? (
match ? (
maxQueryBlockNumber < endBlock$1 ? maxQueryBlockNumber : endBlock$1
) : endBlock$1
) : (
match ? maxQueryBlockNumber : endBlock$1
);
var q = makePartitionQuery(p, indexingContracts, endBlock$2, 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 makeNoItem(param) {
return {
TAG: "NoItem",
latestFetchedBlock: param.latestFetchedBlock
};
}
function getEarliestEvent(fetchState) {
var queue = fetchState.queue;
var item = Utils.$$Array.last(fetchState.queue);
if (item !== undefined) {
var latestOnBlockBlockNumber = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = fetchState.latestFullyFetchedBlock;
if (item.blockNumber <= (
latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber ? latestOnBlockBlockNumber : latestFullyFetchedBlock.blockNumber
)) {
return {
TAG: "Item",
_0: {
item: item,
popItemOffQueue: (function () {
queue.pop();
})
}
};
}
var latestOnBlockBlockNumber$1 = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock$1 = fetchState.latestFullyFetchedBlock;
return {
TAG: "NoItem",
latestFetchedBlock: latestOnBlockBlockNumber$1 < latestFullyFetchedBlock$1.blockNumber ? ({
blockNumber: latestOnBlockBlockNumber$1,
blockTimestamp: 0
}) : latestFullyFetchedBlock$1
};
} else {
var latestOnBlockBlockNumber$2 = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock$2 = fetchState.latestFullyFetchedBlock;
return {
TAG: "NoItem",
latestFetchedBlock: latestOnBlockBlockNumber$2 < latestFullyFetchedBlock$2.blockNumber ? ({
blockNumber: latestOnBlockBlockNumber$2,
blockTimestamp: 0
}) : latestFullyFetchedBlock$2
};
}
}
function make(startBlock, endBlock, eventConfigs, contracts, maxAddrInPartition, chainId, targetBufferSize, progressBlockNumberOpt, onBlockConfigsOpt, blockLagOpt) {
var progressBlockNumber = progressBlockNumberOpt !== undefined ? progressBlockNumberOpt : startBlock - 1 | 0;
var onBlockConfigs = onBlockConfigsOpt !== undefined ? onBlockConfigsOpt : [];
var blockLag = blockLagOpt !== undefined ? blockLagOpt : 0;
var latestFetchedBlock = {
blockNumber: progressBlockNumber,
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(progressBlockNumber, chainId);
if (endBlock !== undefined) {
Prometheus.IndexingEndBlock.set(endBlock, chainId);
}
return {
partitions: partitions,
nextPartitionIndex: partitions.length,
startBlock: startBlock,
endBlock: endBlock,
maxAddrInPartition: maxAddrInPartition,
normalSelection: normalSelection,
indexingContracts: indexingContracts,
contractConfigs: contractConfigs,
dcsToStore: undefined,
chainId: chainId,
latestFullyFetchedBlock: latestFetchedBlock,
latestOnBlockBlockNumber: progressBlockNumber,
blockLag: blockLag,
queue: [],
targetBufferSize: targetBufferSize,
onBlockConfigs: onBlockConfigs
};
}
function bufferSize(param) {
return param.queue.length;
}
function pruneQueueFromFirstChangeEvent(queue, firstChangeEvent) {
return Belt_Array.keep(queue, (function (item) {
var tmp;
tmp = item.kind === 0 ? [
item.blockNumber,
item.logIndex
] : [
item.blockNumber,
item.logIndex
];
return Caml_obj.lessthan(tmp, [
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({
partitions: fetchState.partitions,
nextPartitionIndex: fetchState.nextPartitionIndex,
startBlock: fetchState.startBlock,
endBlock: fetchState.endBlock,
maxAddrInPartition: fetchState.maxAddrInPartition,
normalSelection: fetchState.normalSelection,
indexingContracts: fetchState.indexingContracts,
contractConfigs: fetchState.contractConfigs,
dcsToStore: fetchState.dcsToStore,
chainId: fetchState.chainId,
latestFullyFetchedBlock: fetchState.latestFullyFetchedBlock,
latestOnBlockBlockNumber: firstChangeEvent.blockNumber - 1 | 0,
blockLag: fetchState.blockLag,
queue: fetchState.queue,
targetBufferSize: fetchState.targetBufferSize,
onBlockConfigs: fetchState.onBlockConfigs
}, partitions, undefined, indexingContracts, Caml_option.some(tmp), pruneQueueFromFirstChangeEvent(fetchState.queue, firstChangeEvent), undefined);
}
function isActivelyIndexing(fetchState) {
var endBlock = fetchState.endBlock;
if (endBlock === undefined) {
return true;
}
var latestOnBlockBlockNumber = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = fetchState.latestFullyFetchedBlock;
var isPastEndblock = (
latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber ? latestOnBlockBlockNumber : latestFullyFetchedBlock.blockNumber
) >= endBlock;
if (isPastEndblock) {
return bufferSize(fetchState) > 0;
} else {
return true;
}
}
function isReadyToEnterReorgThreshold(fetchState, currentBlockHeight) {
var blockLag = fetchState.blockLag;
var endBlock = fetchState.endBlock;
var latestOnBlockBlockNumber = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = fetchState.latestFullyFetchedBlock;
var bufferBlockNumber = latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber ? latestOnBlockBlockNumber : latestFullyFetchedBlock.blockNumber;
if (currentBlockHeight !== 0 && (
endBlock !== undefined && bufferBlockNumber >= endBlock ? true : bufferBlockNumber >= (currentBlockHeight - blockLag | 0)
)) {
return Utils.$$Array.isEmpty(fetchState.queue);
} else {
return false;
}
}
function hasBatchItem(fetchState) {
var item = Utils.$$Array.last(fetchState.queue);
if (item === undefined) {
return false;
}
var latestOnBlockBlockNumber = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = fetchState.latestFullyFetchedBlock;
return item.blockNumber <= (
latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber ? latestOnBlockBlockNumber : latestFullyFetchedBlock.blockNumber
);
}
function hasFullBatch(fetchState, maxBatchSize) {
var queue = fetchState.queue;
var targetBlockIdx = queue.length - maxBatchSize | 0;
if (targetBlockIdx < 0) {
return false;
}
var latestOnBlockBlockNumber = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = fetchState.latestFullyFetchedBlock;
return queue[targetBlockIdx].blockNumber <= (
latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber ? latestOnBlockBlockNumber : latestFullyFetchedBlock.blockNumber
);
}
function filterAndSortForUnorderedBatch(fetchStates, maxBatchSize) {
return Belt_Array.keepU(fetchStates, hasBatchItem).sort(function (a, b) {
var match = hasFullBatch(a, maxBatchSize);
var match$1 = hasFullBatch(b, maxBatchSize);
if (match) {
if (!match$1) {
return -1;
}
} else if (match$1) {
return 1;
}
var match$2 = Utils.$$Array.lastUnsafe(a.queue);
var match$3 = Utils.$$Array.lastUnsafe(b.queue);
if (match$2.kind === 0 && match$3.kind === 0) {
return match$2.timestamp - match$3.timestamp | 0;
} else {
return Js_math.random_int(-1, 1);
}
});
}
function getProgressBlockNumber(fetchState) {
var latestOnBlockBlockNumber = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = fetchState.latestFullyFetchedBlock;
var bufferBlockNumber = latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber ? latestOnBlockBlockNumber : latestFullyFetchedBlock.blockNumber;
var item = Utils.$$Array.last(fetchState.queue);
if (item !== undefined && bufferBlockNumber >= item.blockNumber) {
return item.blockNumber - 1 | 0;
} else {
return bufferBlockNumber;
}
}
function getProgressNextBlockLogIndex(fetchState) {
var match = Utils.$$Array.last(fetchState.queue);
if (match === undefined) {
return ;
}
if (match.kind !== 0) {
return ;
}
var logIndex = match.logIndex;
var latestOnBlockBlockNumber = fetchState.latestOnBlockBlockNumber;
var latestFullyFetchedBlock = fetchState.latestFullyFetchedBlock;
if ((
latestOnBlockBlockNumber < latestFullyFetchedBlock.blockNumber ? latestOnBlockBlockNumber : latestFullyFetchedBlock.blockNumber
) >= match.blockNumber && logIndex > 0) {
return logIndex - 1 | 0;
}
}
var blockItemLogIndex = 16777216;
exports.copy = copy;
exports.mergeIntoPartition = mergeIntoPartition;
exports.bufferBlockNumber = bufferBlockNumber;
exports.bufferBlock = bufferBlock;
exports.compareBufferItem = compareBufferItem;
exports.blockItemLogIndex = blockItemLogIndex;
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.makeNoItem = makeNoItem;
exports.getEarliestEvent = getEarliestEvent;
exports.make = make;
exports.bufferSize = bufferSize;
exports.pruneQueueFromFirstChangeEvent = pruneQueueFromFirstChangeEvent;
exports.rollbackPartition = rollbackPartition;
exports.rollback = rollback;
exports.isActivelyIndexing = isActivelyIndexing;
exports.isReadyToEnterReorgThreshold = isReadyToEnterReorgThreshold;
exports.filterAndSortForUnorderedBatch = filterAndSortForUnorderedBatch;
exports.getProgressBlockNumber = getProgressBlockNumber;
exports.getProgressNextBlockLogIndex = getProgressNextBlockLogIndex;
/* Utils Not a pure module */