envio 3.2.1 → 3.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -7
- package/src/Batch.res +12 -15
- package/src/Batch.res.mjs +4 -5
- package/src/BatchProcessing.res +199 -0
- package/src/BatchProcessing.res.mjs +125 -0
- package/src/ChainFetching.res +373 -0
- package/src/ChainFetching.res.mjs +206 -0
- package/src/ChainMetadata.res +27 -0
- package/src/ChainMetadata.res.mjs +27 -0
- package/src/ChainState.res +643 -0
- package/src/ChainState.res.mjs +476 -0
- package/src/ChainState.resi +87 -0
- package/src/Config.res +13 -4
- package/src/Config.res.mjs +8 -3
- package/src/ContractRegisterContext.res +106 -0
- package/src/ContractRegisterContext.res.mjs +76 -0
- package/src/Core.res +3 -0
- package/src/CrossChainState.res +294 -0
- package/src/CrossChainState.res.mjs +221 -0
- package/src/CrossChainState.resi +39 -0
- package/src/Ecosystem.res +58 -0
- package/src/Ecosystem.res.mjs +43 -1
- package/src/Env.res +0 -2
- package/src/Env.res.mjs +0 -3
- package/src/EventConfigBuilder.res +2 -2
- package/src/EventProcessing.res +60 -46
- package/src/EventProcessing.res.mjs +33 -32
- package/src/EventUtils.res +0 -4
- package/src/EventUtils.res.mjs +0 -4
- package/src/ExitOnCaughtUp.res +10 -0
- package/src/ExitOnCaughtUp.res.mjs +22 -0
- package/src/FetchState.res +205 -73
- package/src/FetchState.res.mjs +242 -103
- package/src/InMemoryStore.res +36 -451
- package/src/InMemoryStore.res.mjs +20 -369
- package/src/IndexerLoop.res +43 -0
- package/src/IndexerLoop.res.mjs +46 -0
- package/src/IndexerState.res +536 -0
- package/src/IndexerState.res.mjs +543 -0
- package/src/IndexerState.resi +128 -0
- package/src/Internal.res +29 -8
- package/src/LoadLayer.res +20 -18
- package/src/LoadLayer.res.mjs +14 -12
- package/src/LoadLayer.resi +6 -3
- package/src/Logging.res +11 -44
- package/src/Logging.res.mjs +10 -42
- package/src/Main.res +54 -79
- package/src/Main.res.mjs +44 -56
- package/src/PgStorage.res +8 -71
- package/src/PgStorage.res.mjs +3 -47
- package/src/Prometheus.res +1 -13
- package/src/Prometheus.res.mjs +84 -96
- package/src/PruneStaleHistory.res +45 -0
- package/src/PruneStaleHistory.res.mjs +46 -0
- package/src/RawEvent.res +73 -0
- package/src/RawEvent.res.mjs +51 -0
- package/src/Rollback.res +204 -0
- package/src/Rollback.res.mjs +118 -0
- package/src/SimulateItems.res +12 -10
- package/src/SimulateItems.res.mjs +1 -1
- package/src/UserContext.res +26 -114
- package/src/UserContext.res.mjs +15 -78
- package/src/Writing.res +242 -0
- package/src/Writing.res.mjs +215 -0
- package/src/db/InternalTable.res +14 -27
- package/src/sources/Evm.res +40 -1
- package/src/sources/Evm.res.mjs +94 -84
- package/src/sources/Fuel.res +40 -1
- package/src/sources/Fuel.res.mjs +36 -26
- package/src/sources/HyperFuel.res +41 -120
- package/src/sources/HyperFuel.res.mjs +42 -80
- package/src/sources/HyperFuel.resi +1 -24
- package/src/sources/HyperFuelClient.res +16 -297
- package/src/sources/HyperFuelClient.res.mjs +5 -4
- package/src/sources/HyperFuelSource.res +33 -8
- package/src/sources/HyperFuelSource.res.mjs +56 -10
- package/src/sources/HyperSyncSource.res +5 -3
- package/src/sources/HyperSyncSource.res.mjs +1 -1
- package/src/sources/RpcSource.res +2 -2
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/SourceManager.res +14 -23
- package/src/sources/SourceManager.res.mjs +27 -29
- package/src/sources/SourceManager.resi +4 -2
- package/src/sources/Svm.res +18 -1
- package/src/sources/Svm.res.mjs +30 -22
- package/src/sources/SvmHyperSyncSource.res +1 -1
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/src/tui/Tui.res +38 -36
- package/src/tui/Tui.res.mjs +51 -51
- package/src/ChainFetcher.res +0 -519
- package/src/ChainFetcher.res.mjs +0 -314
- package/src/ChainManager.res +0 -358
- package/src/ChainManager.res.mjs +0 -291
- package/src/Ctx.res +0 -6
- package/src/Ctx.res.mjs +0 -2
- package/src/GlobalState.res +0 -1056
- package/src/GlobalState.res.mjs +0 -1086
- package/src/GlobalStateManager.res +0 -57
- package/src/GlobalStateManager.res.mjs +0 -68
- package/src/GlobalStateManager.resi +0 -7
- package/src/Ports.res +0 -5
- package/src/Ports.res.mjs +0 -9
- package/src/adapters/MarkBatchProcessedAdapter.res +0 -5
- package/src/adapters/MarkBatchProcessedAdapter.res.mjs +0 -14
- package/src/sources/EnvioApiClient.res +0 -15
- package/src/sources/EnvioApiClient.res.mjs +0 -24
package/src/ChainFetcher.res.mjs
DELETED
|
@@ -1,314 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Env from "./Env.res.mjs";
|
|
4
|
-
import * as Svm from "./sources/Svm.res.mjs";
|
|
5
|
-
import * as Utils from "./Utils.res.mjs";
|
|
6
|
-
import * as Logging from "./Logging.res.mjs";
|
|
7
|
-
import * as ChainMap from "./ChainMap.res.mjs";
|
|
8
|
-
import * as EvmChain from "./sources/EvmChain.res.mjs";
|
|
9
|
-
import * as FetchState from "./FetchState.res.mjs";
|
|
10
|
-
import * as Prometheus from "./Prometheus.res.mjs";
|
|
11
|
-
import * as EventRouter from "./sources/EventRouter.res.mjs";
|
|
12
|
-
import * as UserContext from "./UserContext.res.mjs";
|
|
13
|
-
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
14
|
-
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
15
|
-
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
16
|
-
import * as SourceManager from "./sources/SourceManager.res.mjs";
|
|
17
|
-
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
18
|
-
import * as ReorgDetection from "./ReorgDetection.res.mjs";
|
|
19
|
-
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
20
|
-
import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
|
|
21
|
-
import * as HyperFuelSource from "./sources/HyperFuelSource.res.mjs";
|
|
22
|
-
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
23
|
-
import * as SvmHyperSyncSource from "./sources/SvmHyperSyncSource.res.mjs";
|
|
24
|
-
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
25
|
-
import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
|
|
26
|
-
|
|
27
|
-
function configAddresses(chainConfig) {
|
|
28
|
-
let addresses = [];
|
|
29
|
-
chainConfig.contracts.forEach(contract => {
|
|
30
|
-
contract.addresses.forEach(address => {
|
|
31
|
-
addresses.push({
|
|
32
|
-
address: address,
|
|
33
|
-
contractName: contract.name,
|
|
34
|
-
registrationBlock: -1
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
return addresses;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function make(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBlockOpt, progressBlockNumber, config, registrations, targetBufferSize, logger, timestampCaughtUpToHeadOrEndblock, numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, maxReorgDepth, knownHeightOpt, reducedPollingInterval) {
|
|
42
|
-
let firstEventBlock = firstEventBlockOpt !== undefined ? Primitive_option.valFromOption(firstEventBlockOpt) : undefined;
|
|
43
|
-
let knownHeight = knownHeightOpt !== undefined ? knownHeightOpt : 0;
|
|
44
|
-
let eventRouter = EventRouter.empty();
|
|
45
|
-
let eventConfigs = [];
|
|
46
|
-
let notRegisteredEvents = [];
|
|
47
|
-
chainConfig.contracts.forEach(contract => {
|
|
48
|
-
let contractName = contract.name;
|
|
49
|
-
contract.events.forEach(eventConfig => {
|
|
50
|
-
let hasContractRegister = Stdlib_Option.isSome(eventConfig.contractRegister);
|
|
51
|
-
EventRouter.addOrThrow(eventRouter, eventConfig.id, undefined, contractName, eventConfig.isWildcard, eventConfig.name, ChainMap.Chain.makeUnsafe(chainConfig.id));
|
|
52
|
-
let shouldBeIncluded;
|
|
53
|
-
if (config.enableRawEvents) {
|
|
54
|
-
shouldBeIncluded = true;
|
|
55
|
-
} else {
|
|
56
|
-
let isRegistered = hasContractRegister || Stdlib_Option.isSome(eventConfig.handler);
|
|
57
|
-
if (!isRegistered) {
|
|
58
|
-
notRegisteredEvents.push(eventConfig);
|
|
59
|
-
}
|
|
60
|
-
shouldBeIncluded = isRegistered;
|
|
61
|
-
}
|
|
62
|
-
let shouldSkip;
|
|
63
|
-
try {
|
|
64
|
-
let getEventFiltersOrThrow = eventConfig.getEventFiltersOrThrow;
|
|
65
|
-
if (getEventFiltersOrThrow) {
|
|
66
|
-
let match = getEventFiltersOrThrow(ChainMap.Chain.makeUnsafe(chainConfig.id));
|
|
67
|
-
shouldSkip = match.TAG === "Static" ? match._0.length === 0 : false;
|
|
68
|
-
} else {
|
|
69
|
-
shouldSkip = false;
|
|
70
|
-
}
|
|
71
|
-
} catch (exn) {
|
|
72
|
-
shouldSkip = false;
|
|
73
|
-
}
|
|
74
|
-
if (shouldBeIncluded && !shouldSkip) {
|
|
75
|
-
eventConfigs.push(eventConfig);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
let startBlock = contract.startBlock;
|
|
80
|
-
if (startBlock !== undefined && startBlock < chainConfig.startBlock) {
|
|
81
|
-
return Stdlib_JsError.throwWithMessage(`The start block for contract "` + contractName + `" is less than the chain start block. This is not supported yet.`);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
if (Utils.$$Array.notEmpty(notRegisteredEvents)) {
|
|
85
|
-
Logging.childInfo(logger, `The event` + (
|
|
86
|
-
notRegisteredEvents.length > 1 ? "s" : ""
|
|
87
|
-
) + ` ` + notRegisteredEvents.map(eventConfig => eventConfig.contractName + `.` + eventConfig.name).join(", ") + ` don't have an event handler and skipped for indexing.`);
|
|
88
|
-
}
|
|
89
|
-
let onBlockConfigs = registrations.onBlockByChainId[chainConfig.id.toString()];
|
|
90
|
-
if (onBlockConfigs !== undefined) {
|
|
91
|
-
onBlockConfigs.forEach(onBlockConfig => {
|
|
92
|
-
if (Stdlib_Option.getOr(onBlockConfig.startBlock, startBlock) < startBlock) {
|
|
93
|
-
Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + onBlockConfig.name + `" is less than the chain start block (` + startBlock.toString() + `). This is not supported yet.`);
|
|
94
|
-
}
|
|
95
|
-
if (endBlock !== undefined && Stdlib_Option.getOr(onBlockConfig.endBlock, endBlock) > endBlock) {
|
|
96
|
-
return Stdlib_JsError.throwWithMessage(`The end block for onBlock handler "` + onBlockConfig.name + `" is greater than the chain end block (` + endBlock.toString() + `). This is not supported yet.`);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
let fetchState = FetchState.make(startBlock, endBlock, eventConfigs, indexingAddresses, config.maxAddrInPartition, chainConfig.id, targetBufferSize, knownHeight, progressBlockNumber, onBlockConfigs, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock));
|
|
101
|
-
let chainReorgCheckpoints = Stdlib_Array.filterMap(reorgCheckpoints, reorgCheckpoint => {
|
|
102
|
-
if (reorgCheckpoint.chain_id === chainConfig.id) {
|
|
103
|
-
return reorgCheckpoint;
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
let chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
|
|
107
|
-
let lowercaseAddresses = config.lowercaseAddresses;
|
|
108
|
-
let sources = chainConfig.sourceConfig;
|
|
109
|
-
let sources$1;
|
|
110
|
-
switch (sources.TAG) {
|
|
111
|
-
case "EvmSourceConfig" :
|
|
112
|
-
let evmContracts = chainConfig.contracts.map(contract => ({
|
|
113
|
-
name: contract.name,
|
|
114
|
-
abi: contract.abi,
|
|
115
|
-
events: contract.events
|
|
116
|
-
}));
|
|
117
|
-
let evmRpcs = sources.rpcs.map(rpc => {
|
|
118
|
-
let syncConfig = rpc.syncConfig;
|
|
119
|
-
let ws = rpc.ws;
|
|
120
|
-
return {
|
|
121
|
-
url: rpc.url,
|
|
122
|
-
sourceFor: rpc.sourceFor,
|
|
123
|
-
syncConfig: syncConfig,
|
|
124
|
-
ws: ws
|
|
125
|
-
};
|
|
126
|
-
});
|
|
127
|
-
sources$1 = EvmChain.makeSources(chain, evmContracts, sources.hypersync, evmRpcs, lowercaseAddresses);
|
|
128
|
-
break;
|
|
129
|
-
case "FuelSourceConfig" :
|
|
130
|
-
sources$1 = [HyperFuelSource.make({
|
|
131
|
-
chain: chain,
|
|
132
|
-
endpointUrl: sources.hypersync
|
|
133
|
-
})];
|
|
134
|
-
break;
|
|
135
|
-
case "SvmSourceConfig" :
|
|
136
|
-
let rpc = sources.rpc;
|
|
137
|
-
let hypersync = sources.hypersync;
|
|
138
|
-
if (hypersync !== undefined) {
|
|
139
|
-
let svmEventConfigs = chainConfig.contracts.flatMap(contract => contract.events);
|
|
140
|
-
sources$1 = [SvmHyperSyncSource.make({
|
|
141
|
-
chain: chain,
|
|
142
|
-
endpointUrl: hypersync,
|
|
143
|
-
apiToken: Env.envioApiToken,
|
|
144
|
-
eventConfigs: svmEventConfigs,
|
|
145
|
-
clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis
|
|
146
|
-
})];
|
|
147
|
-
} else {
|
|
148
|
-
sources$1 = rpc !== undefined ? [Svm.makeRPCSource(chain, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + chain.toString() + ` has no SVM data source`);
|
|
149
|
-
}
|
|
150
|
-
break;
|
|
151
|
-
case "CustomSources" :
|
|
152
|
-
sources$1 = sources._0;
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
return {
|
|
156
|
-
logger: logger,
|
|
157
|
-
fetchState: fetchState,
|
|
158
|
-
sourceManager: SourceManager.make(sources$1, Env.maxPartitionConcurrency, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined),
|
|
159
|
-
chainConfig: chainConfig,
|
|
160
|
-
isProgressAtHead: false,
|
|
161
|
-
timestampCaughtUpToHeadOrEndblock: timestampCaughtUpToHeadOrEndblock,
|
|
162
|
-
committedProgressBlockNumber: progressBlockNumber,
|
|
163
|
-
numEventsProcessed: numEventsProcessed,
|
|
164
|
-
reorgDetection: ReorgDetection.make(chainReorgCheckpoints, maxReorgDepth, config.shouldRollbackOnReorg),
|
|
165
|
-
safeCheckpointTracking: SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function makeFromConfig(chainConfig, config, registrations, targetBufferSize, knownHeight) {
|
|
170
|
-
let logger = Logging.createChild({
|
|
171
|
-
chainId: chainConfig.id
|
|
172
|
-
});
|
|
173
|
-
return make(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrations, targetBufferSize, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrations, targetBufferSize, reducedPollingInterval) {
|
|
177
|
-
let chainId = chainConfig.id;
|
|
178
|
-
let logger = Logging.createChild({
|
|
179
|
-
chainId: chainId
|
|
180
|
-
});
|
|
181
|
-
Prometheus.ProgressEventsCount.set(resumedChainState.numEventsProcessed, chainId);
|
|
182
|
-
let progressBlockNumber = resumedChainState.progressBlockNumber >= 0 ? resumedChainState.progressBlockNumber : resumedChainState.startBlock - 1 | 0;
|
|
183
|
-
return make(chainConfig, resumedChainState.indexingAddresses, resumedChainState.startBlock, resumedChainState.endBlock, Primitive_option.some(resumedChainState.firstEventBlockNumber), progressBlockNumber, config, registrations, targetBufferSize, logger, Env.updateSyncTimeOnRestart ? undefined : resumedChainState.timestampCaughtUpToHeadOrEndblock, resumedChainState.numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, resumedChainState.maxReorgDepth, resumedChainState.sourceBlockNumber, reducedPollingInterval);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async function runContractRegistersOrThrow(itemsWithContractRegister, config) {
|
|
187
|
-
let itemsWithDcs = [];
|
|
188
|
-
let onRegister = (item, contractAddress, contractName) => {
|
|
189
|
-
let dc_registrationBlock = item.blockNumber;
|
|
190
|
-
let dc = {
|
|
191
|
-
address: contractAddress,
|
|
192
|
-
contractName: contractName,
|
|
193
|
-
registrationBlock: dc_registrationBlock
|
|
194
|
-
};
|
|
195
|
-
let dcs = item.dcs;
|
|
196
|
-
if (dcs !== undefined) {
|
|
197
|
-
dcs.push(dc);
|
|
198
|
-
} else {
|
|
199
|
-
item.dcs = [dc];
|
|
200
|
-
itemsWithDcs.push(item);
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
let promises = [];
|
|
204
|
-
for (let idx = 0, idx_finish = itemsWithContractRegister.length; idx < idx_finish; ++idx) {
|
|
205
|
-
let item = itemsWithContractRegister[idx];
|
|
206
|
-
let match = item.eventConfig;
|
|
207
|
-
let contractRegister = match.contractRegister;
|
|
208
|
-
let contractRegister$1 = contractRegister !== undefined ? contractRegister : Stdlib_JsError.throwWithMessage("Contract register is not set for event " + match.name);
|
|
209
|
-
let errorMessage = "Event contractRegister failed, please fix the error to keep the indexer running smoothly";
|
|
210
|
-
try {
|
|
211
|
-
let params = {
|
|
212
|
-
item: item,
|
|
213
|
-
onRegister: onRegister,
|
|
214
|
-
config: config,
|
|
215
|
-
isResolved: false
|
|
216
|
-
};
|
|
217
|
-
let result = contractRegister$1(UserContext.getContractRegisterArgs(params));
|
|
218
|
-
if (Utils.$$Promise.isCatchable(result)) {
|
|
219
|
-
promises.push(Stdlib_Promise.$$catch(result.then(r => {
|
|
220
|
-
params.isResolved = true;
|
|
221
|
-
|
|
222
|
-
}), exn => {
|
|
223
|
-
params.isResolved = true;
|
|
224
|
-
return ErrorHandling.mkLogAndRaise(Logging.getItemLogger(item), errorMessage, exn);
|
|
225
|
-
}));
|
|
226
|
-
} else {
|
|
227
|
-
params.isResolved = true;
|
|
228
|
-
}
|
|
229
|
-
} catch (raw_exn) {
|
|
230
|
-
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
231
|
-
ErrorHandling.mkLogAndRaise(Logging.getItemLogger(item), errorMessage, exn);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (Utils.$$Array.notEmpty(promises)) {
|
|
235
|
-
await Promise.all(promises);
|
|
236
|
-
}
|
|
237
|
-
return itemsWithDcs;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function handleQueryResult(chainFetcher, query, newItems, newItemsWithDcs, latestFetchedBlock, knownHeight) {
|
|
241
|
-
let fs = newItemsWithDcs.length !== 0 ? FetchState.registerDynamicContracts(chainFetcher.fetchState, newItemsWithDcs) : chainFetcher.fetchState;
|
|
242
|
-
return {
|
|
243
|
-
logger: chainFetcher.logger,
|
|
244
|
-
fetchState: FetchState.updateKnownHeight(FetchState.handleQueryResult(fs, query, latestFetchedBlock, newItems), knownHeight),
|
|
245
|
-
sourceManager: chainFetcher.sourceManager,
|
|
246
|
-
chainConfig: chainFetcher.chainConfig,
|
|
247
|
-
isProgressAtHead: chainFetcher.isProgressAtHead,
|
|
248
|
-
timestampCaughtUpToHeadOrEndblock: chainFetcher.timestampCaughtUpToHeadOrEndblock,
|
|
249
|
-
committedProgressBlockNumber: chainFetcher.committedProgressBlockNumber,
|
|
250
|
-
numEventsProcessed: chainFetcher.numEventsProcessed,
|
|
251
|
-
reorgDetection: chainFetcher.reorgDetection,
|
|
252
|
-
safeCheckpointTracking: chainFetcher.safeCheckpointTracking
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function hasProcessedToEndblock(self) {
|
|
257
|
-
let endBlock = self.fetchState.endBlock;
|
|
258
|
-
if (endBlock !== undefined) {
|
|
259
|
-
return self.committedProgressBlockNumber >= endBlock;
|
|
260
|
-
} else {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function hasNoMoreEventsToProcess(self) {
|
|
266
|
-
return FetchState.bufferSize(self.fetchState) === 0;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function getHighestBlockBelowThreshold(cf) {
|
|
270
|
-
let highestBlockBelowThreshold = cf.fetchState.knownHeight - cf.chainConfig.maxReorgDepth | 0;
|
|
271
|
-
if (highestBlockBelowThreshold < 0) {
|
|
272
|
-
return 0;
|
|
273
|
-
} else {
|
|
274
|
-
return highestBlockBelowThreshold;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
async function getLastKnownValidBlock(chainFetcher, reorgBlockNumber, isRealtime) {
|
|
279
|
-
let scannedBlockNumbers = ReorgDetection.getThresholdBlockNumbersBelowBlock(chainFetcher.reorgDetection, reorgBlockNumber, chainFetcher.fetchState.knownHeight);
|
|
280
|
-
if (scannedBlockNumbers.length === 0) {
|
|
281
|
-
return getHighestBlockBelowThreshold(chainFetcher);
|
|
282
|
-
}
|
|
283
|
-
let blockNumbersAndHashes = await SourceManager.getBlockHashes(chainFetcher.sourceManager, scannedBlockNumbers, isRealtime);
|
|
284
|
-
let blockNumber = ReorgDetection.getLatestValidScannedBlock(chainFetcher.reorgDetection, blockNumbersAndHashes);
|
|
285
|
-
if (blockNumber !== undefined) {
|
|
286
|
-
return blockNumber;
|
|
287
|
-
} else {
|
|
288
|
-
return getHighestBlockBelowThreshold(chainFetcher);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function isActivelyIndexing(chainFetcher) {
|
|
293
|
-
return FetchState.isActivelyIndexing(chainFetcher.fetchState);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function isReady(chainFetcher) {
|
|
297
|
-
return chainFetcher.timestampCaughtUpToHeadOrEndblock !== undefined;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
export {
|
|
301
|
-
configAddresses,
|
|
302
|
-
make,
|
|
303
|
-
makeFromConfig,
|
|
304
|
-
makeFromDbState,
|
|
305
|
-
runContractRegistersOrThrow,
|
|
306
|
-
handleQueryResult,
|
|
307
|
-
hasProcessedToEndblock,
|
|
308
|
-
hasNoMoreEventsToProcess,
|
|
309
|
-
getHighestBlockBelowThreshold,
|
|
310
|
-
getLastKnownValidBlock,
|
|
311
|
-
isActivelyIndexing,
|
|
312
|
-
isReady,
|
|
313
|
-
}
|
|
314
|
-
/* Env Not a pure module */
|
package/src/ChainManager.res
DELETED
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
type t = {
|
|
2
|
-
chainFetchers: ChainMap.t<ChainFetcher.t>,
|
|
3
|
-
isInReorgThreshold: bool,
|
|
4
|
-
// True once every chain has caught up to head/endBlock. Monotonic during a run.
|
|
5
|
-
isRealtime: bool,
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// Check if progress is past the reorg threshold (safe block).
|
|
9
|
-
// A chain is in reorg threshold when progressBlockNumber > sourceBlockNumber - maxReorgDepth.
|
|
10
|
-
// This matches the logic in InternalTable.Checkpoints.makeGetReorgCheckpointsQuery.
|
|
11
|
-
let isProgressInReorgThreshold = (~progressBlockNumber, ~sourceBlockNumber, ~maxReorgDepth) => {
|
|
12
|
-
maxReorgDepth > 0 &&
|
|
13
|
-
sourceBlockNumber > 0 &&
|
|
14
|
-
progressBlockNumber > sourceBlockNumber - maxReorgDepth
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
let calculateTargetBufferSize = (~activeChainsCount) => {
|
|
18
|
-
switch Env.targetBufferSize {
|
|
19
|
-
| Some(size) => size
|
|
20
|
-
| None =>
|
|
21
|
-
switch activeChainsCount {
|
|
22
|
-
| 1 => 60_000
|
|
23
|
-
| 2 => 30_000
|
|
24
|
-
| 3 => 20_000
|
|
25
|
-
| 4 => 15_000
|
|
26
|
-
| 5 => 10_000
|
|
27
|
-
| _ => 5_000
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
let makeFromDbState = (
|
|
33
|
-
~initialState: Persistence.initialState,
|
|
34
|
-
~config: Config.t,
|
|
35
|
-
~registrations,
|
|
36
|
-
~reducedPollingInterval=?,
|
|
37
|
-
): t => {
|
|
38
|
-
let isInReorgThreshold = if initialState.cleanRun {
|
|
39
|
-
false
|
|
40
|
-
} else {
|
|
41
|
-
// Check if any chain is in reorg threshold by comparing progress with sourceBlock - maxReorgDepth.
|
|
42
|
-
initialState.chains->Array.some(chain =>
|
|
43
|
-
isProgressInReorgThreshold(
|
|
44
|
-
~progressBlockNumber=chain.progressBlockNumber,
|
|
45
|
-
~sourceBlockNumber=chain.sourceBlockNumber,
|
|
46
|
-
~maxReorgDepth=chain.maxReorgDepth,
|
|
47
|
-
)
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
let targetBufferSize = calculateTargetBufferSize(
|
|
52
|
-
~activeChainsCount=initialState.chains->Array.length,
|
|
53
|
-
)
|
|
54
|
-
Prometheus.ProcessingMaxBatchSize.set(~maxBatchSize=config.batchSize)
|
|
55
|
-
Prometheus.IndexingTargetBufferSize.set(~targetBufferSize)
|
|
56
|
-
Prometheus.ReorgThreshold.set(~isInReorgThreshold)
|
|
57
|
-
initialState.cache->Utils.Dict.forEach(({effectName, count}) => {
|
|
58
|
-
Prometheus.EffectCacheCount.set(~count, ~effectName)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
// updateSyncTimeOnRestart wipes the saved timestamp so a restart re-enters
|
|
62
|
-
// backfill mode for all chains.
|
|
63
|
-
let isRealtime =
|
|
64
|
-
!Env.updateSyncTimeOnRestart &&
|
|
65
|
-
initialState.chains->Array.length > 0 &&
|
|
66
|
-
initialState.chains->Array.every(c => c.timestampCaughtUpToHeadOrEndblock->Option.isSome)
|
|
67
|
-
|
|
68
|
-
let chainFetchersArr =
|
|
69
|
-
initialState.chains->Array.map((resumedChainState: Persistence.initialChainState) => {
|
|
70
|
-
let chain = Config.getChain(config, ~chainId=resumedChainState.id)
|
|
71
|
-
let chainConfig = config.chainMap->ChainMap.get(chain)
|
|
72
|
-
|
|
73
|
-
(
|
|
74
|
-
chain,
|
|
75
|
-
chainConfig->ChainFetcher.makeFromDbState(
|
|
76
|
-
~resumedChainState,
|
|
77
|
-
~reorgCheckpoints=initialState.reorgCheckpoints,
|
|
78
|
-
~isInReorgThreshold,
|
|
79
|
-
~isRealtime,
|
|
80
|
-
~targetBufferSize,
|
|
81
|
-
~config,
|
|
82
|
-
~registrations,
|
|
83
|
-
~reducedPollingInterval?,
|
|
84
|
-
),
|
|
85
|
-
)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
let chainFetchers = ChainMap.fromArrayUnsafe(chainFetchersArr)
|
|
89
|
-
|
|
90
|
-
// Set initial progress metrics from DB state so dashboards reflect
|
|
91
|
-
// the persisted state immediately on restart
|
|
92
|
-
let allChainsReady = ref(chainFetchersArr->Array.length > 0)
|
|
93
|
-
chainFetchersArr->Array.forEach(((chain, cf)) => {
|
|
94
|
-
let chainId = chain->ChainMap.Chain.toChainId
|
|
95
|
-
Prometheus.ProgressBlockNumber.set(~blockNumber=cf.committedProgressBlockNumber, ~chainId)
|
|
96
|
-
Prometheus.ProgressReady.init(~chainId)
|
|
97
|
-
if cf->ChainFetcher.isReady {
|
|
98
|
-
Prometheus.ProgressReady.set(~chainId)
|
|
99
|
-
} else {
|
|
100
|
-
allChainsReady := false
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
if allChainsReady.contents {
|
|
104
|
-
Prometheus.ProgressReady.setAllReady()
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
{
|
|
108
|
-
chainFetchers,
|
|
109
|
-
isInReorgThreshold,
|
|
110
|
-
isRealtime,
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
let getChainFetcher = (chainManager: t, ~chain: ChainMap.Chain.t): ChainFetcher.t => {
|
|
115
|
-
chainManager.chainFetchers->ChainMap.get(chain)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let setChainFetcher = (chainManager: t, chainFetcher: ChainFetcher.t) => {
|
|
119
|
-
{
|
|
120
|
-
...chainManager,
|
|
121
|
-
chainFetchers: chainManager.chainFetchers->ChainMap.set(
|
|
122
|
-
ChainMap.Chain.makeUnsafe(~chainId=chainFetcher.chainConfig.id),
|
|
123
|
-
chainFetcher,
|
|
124
|
-
),
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
let nextItemIsNone = (chainManager: t): bool => {
|
|
129
|
-
!Batch.hasReadyItem(
|
|
130
|
-
chainManager.chainFetchers->ChainMap.map(cf => {
|
|
131
|
-
cf.fetchState
|
|
132
|
-
}),
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
let createBatch = (
|
|
137
|
-
chainManager: t,
|
|
138
|
-
~processedCheckpointId,
|
|
139
|
-
~batchSizeTarget: int,
|
|
140
|
-
~isRollback: bool,
|
|
141
|
-
): Batch.t => {
|
|
142
|
-
Batch.make(
|
|
143
|
-
~isInReorgThreshold=chainManager.isInReorgThreshold,
|
|
144
|
-
~checkpointIdBeforeBatch=processedCheckpointId->BigInt.add(
|
|
145
|
-
// Since for rollback we have a diff checkpoint id.
|
|
146
|
-
// This is needed to currectly overwrite old state
|
|
147
|
-
// in an append-only ClickHouse insert.
|
|
148
|
-
isRollback ? 1n : 0n,
|
|
149
|
-
),
|
|
150
|
-
~chainsBeforeBatch=chainManager.chainFetchers->ChainMap.map((cf): Batch.chainBeforeBatch => {
|
|
151
|
-
fetchState: cf.fetchState,
|
|
152
|
-
progressBlockNumber: cf.committedProgressBlockNumber,
|
|
153
|
-
totalEventsProcessed: cf.numEventsProcessed,
|
|
154
|
-
sourceBlockNumber: cf.fetchState.knownHeight,
|
|
155
|
-
reorgDetection: cf.reorgDetection,
|
|
156
|
-
chainConfig: cf.chainConfig,
|
|
157
|
-
}),
|
|
158
|
-
~batchSizeTarget,
|
|
159
|
-
)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
let isProgressAtHead = chainManager =>
|
|
163
|
-
chainManager.chainFetchers->ChainMap.values->Array.every(cf => cf.isProgressAtHead)
|
|
164
|
-
|
|
165
|
-
let isActivelyIndexing = chainManager =>
|
|
166
|
-
chainManager.chainFetchers->ChainMap.values->Array.every(ChainFetcher.isActivelyIndexing)
|
|
167
|
-
|
|
168
|
-
let getSafeCheckpointId = (chainManager: t) => {
|
|
169
|
-
let chainFetchers = chainManager.chainFetchers->ChainMap.values
|
|
170
|
-
|
|
171
|
-
let result: ref<option<bigint>> = ref(None)
|
|
172
|
-
|
|
173
|
-
for idx in 0 to chainFetchers->Array.length - 1 {
|
|
174
|
-
let chainFetcher = chainFetchers->Array.getUnsafe(idx)
|
|
175
|
-
switch chainFetcher.safeCheckpointTracking {
|
|
176
|
-
| None => () // Skip chains with maxReorgDepth = 0
|
|
177
|
-
| Some(safeCheckpointTracking) => {
|
|
178
|
-
let safeCheckpointId =
|
|
179
|
-
safeCheckpointTracking->SafeCheckpointTracking.getSafeCheckpointId(
|
|
180
|
-
~sourceBlockNumber=chainFetcher.fetchState.knownHeight,
|
|
181
|
-
)
|
|
182
|
-
switch result.contents {
|
|
183
|
-
| None => result := Some(safeCheckpointId)
|
|
184
|
-
| Some(current) if safeCheckpointId < current => result := Some(safeCheckpointId)
|
|
185
|
-
| _ => ()
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
switch result.contents {
|
|
192
|
-
| Some(id) if id > 0n => Some(id)
|
|
193
|
-
| _ => None // No safe checkpoint found
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
Takes in a chain manager and sets all chains timestamp caught up to head
|
|
199
|
-
when valid state lines up and returns an updated chain manager
|
|
200
|
-
*/
|
|
201
|
-
let updateProgressedChains = (chainManager: t, ~batch: Batch.t) => {
|
|
202
|
-
let nextQueueItemIsNone = chainManager->nextItemIsNone
|
|
203
|
-
|
|
204
|
-
let allChainsAtHead = chainManager->isProgressAtHead
|
|
205
|
-
//Update the timestampCaughtUpToHeadOrEndblock values
|
|
206
|
-
let allChainsReady = ref(true)
|
|
207
|
-
let chainFetchers = chainManager.chainFetchers->ChainMap.map(prev => {
|
|
208
|
-
let cf = prev
|
|
209
|
-
let chain = ChainMap.Chain.makeUnsafe(~chainId=cf.chainConfig.id)
|
|
210
|
-
|
|
211
|
-
let maybeChainAfterBatch =
|
|
212
|
-
batch.progressedChainsById->Utils.Dict.dangerouslyGetByIntNonOption(
|
|
213
|
-
chain->ChainMap.Chain.toChainId,
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
let cf = switch maybeChainAfterBatch {
|
|
217
|
-
| Some(chainAfterBatch) => {
|
|
218
|
-
if cf.committedProgressBlockNumber !== chainAfterBatch.progressBlockNumber {
|
|
219
|
-
Prometheus.ProgressBlockNumber.set(
|
|
220
|
-
~blockNumber=chainAfterBatch.progressBlockNumber,
|
|
221
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
222
|
-
)
|
|
223
|
-
}
|
|
224
|
-
if cf.numEventsProcessed !== chainAfterBatch.totalEventsProcessed {
|
|
225
|
-
Prometheus.ProgressEventsCount.set(
|
|
226
|
-
~processedCount=chainAfterBatch.totalEventsProcessed,
|
|
227
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
228
|
-
)
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Calculate and set latency metrics
|
|
232
|
-
switch batch->Batch.findLastEventItem(~chainId=chain->ChainMap.Chain.toChainId) {
|
|
233
|
-
| Some(eventItem) => {
|
|
234
|
-
let blockTimestamp = eventItem.timestamp
|
|
235
|
-
let currentTimeMs = Date.now()->Float.toInt
|
|
236
|
-
let blockTimestampMs = blockTimestamp * 1000
|
|
237
|
-
let latencyMs = currentTimeMs - blockTimestampMs
|
|
238
|
-
|
|
239
|
-
Prometheus.ProgressLatency.set(~latencyMs, ~chainId=chain->ChainMap.Chain.toChainId)
|
|
240
|
-
}
|
|
241
|
-
| None => ()
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
{
|
|
245
|
-
...cf,
|
|
246
|
-
// Since we process per chain always in order,
|
|
247
|
-
// we need to calculate it once, by using the first item in a batch
|
|
248
|
-
fetchState: switch cf.fetchState.firstEventBlock {
|
|
249
|
-
| Some(_) => cf.fetchState
|
|
250
|
-
| None =>
|
|
251
|
-
switch batch->Batch.findFirstEventBlockNumber(
|
|
252
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
253
|
-
) {
|
|
254
|
-
| Some(_) as firstEventBlock => {...cf.fetchState, firstEventBlock}
|
|
255
|
-
| None => cf.fetchState
|
|
256
|
-
}
|
|
257
|
-
},
|
|
258
|
-
committedProgressBlockNumber: chainAfterBatch.progressBlockNumber,
|
|
259
|
-
numEventsProcessed: chainAfterBatch.totalEventsProcessed,
|
|
260
|
-
isProgressAtHead: cf.isProgressAtHead || chainAfterBatch.isProgressAtHeadWhenBatchCreated,
|
|
261
|
-
safeCheckpointTracking: switch cf.safeCheckpointTracking {
|
|
262
|
-
| Some(safeCheckpointTracking) =>
|
|
263
|
-
Some(
|
|
264
|
-
safeCheckpointTracking->SafeCheckpointTracking.updateOnNewBatch(
|
|
265
|
-
~sourceBlockNumber=cf.fetchState.knownHeight,
|
|
266
|
-
~chainId=chain->ChainMap.Chain.toChainId,
|
|
267
|
-
~batchCheckpointIds=batch.checkpointIds,
|
|
268
|
-
~batchCheckpointBlockNumbers=batch.checkpointBlockNumbers,
|
|
269
|
-
~batchCheckpointChainIds=batch.checkpointChainIds,
|
|
270
|
-
),
|
|
271
|
-
)
|
|
272
|
-
| None => None
|
|
273
|
-
},
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
| None => cf
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/* strategy for TUI synced status:
|
|
280
|
-
* Firstly -> only update synced status after batch is processed (not on batch creation). But also set when a batch tries to be created and there is no batch
|
|
281
|
-
*
|
|
282
|
-
* Secondly -> reset timestampCaughtUpToHead and isFetching at head when dynamic contracts get registered to a chain if they are not within 0.001 percent of the current block height
|
|
283
|
-
*
|
|
284
|
-
* New conditions for valid synced:
|
|
285
|
-
*
|
|
286
|
-
* CASE 1 (chains are being synchronised at the head)
|
|
287
|
-
*
|
|
288
|
-
* All chain fetchers are fetching at the head AND
|
|
289
|
-
* No events that can be processed on the queue (even if events still exist on the individual queues)
|
|
290
|
-
* CASE 2 (chain finishes earlier than any other chain)
|
|
291
|
-
*
|
|
292
|
-
* CASE 3 endblock has been reached and latest processed block is greater than or equal to endblock (both fields must be Some)
|
|
293
|
-
*
|
|
294
|
-
* The given chain fetcher is fetching at the head or latest processed block >= endblock
|
|
295
|
-
* The given chain has processed all events on the queue
|
|
296
|
-
* see https://github.com/Float-Capital/indexer/pull/1388 */
|
|
297
|
-
let cf = if cf->ChainFetcher.hasProcessedToEndblock {
|
|
298
|
-
// in the case this is already set, don't reset and instead propagate the existing value
|
|
299
|
-
let timestampCaughtUpToHeadOrEndblock =
|
|
300
|
-
cf->ChainFetcher.isReady ? cf.timestampCaughtUpToHeadOrEndblock : Date.make()->Some
|
|
301
|
-
{
|
|
302
|
-
...cf,
|
|
303
|
-
timestampCaughtUpToHeadOrEndblock,
|
|
304
|
-
}
|
|
305
|
-
} else if !(cf->ChainFetcher.isReady) && cf.isProgressAtHead {
|
|
306
|
-
//Only calculate and set timestampCaughtUpToHeadOrEndblock if chain fetcher is at the head and
|
|
307
|
-
//its not already set
|
|
308
|
-
//CASE1
|
|
309
|
-
//All chains are caught up to head chainManager queue returns None
|
|
310
|
-
//Meaning we are busy synchronizing chains at the head
|
|
311
|
-
if nextQueueItemIsNone && allChainsAtHead {
|
|
312
|
-
{
|
|
313
|
-
...cf,
|
|
314
|
-
timestampCaughtUpToHeadOrEndblock: Date.make()->Some,
|
|
315
|
-
}
|
|
316
|
-
} else {
|
|
317
|
-
//CASE2 -> Only calculate if case1 fails
|
|
318
|
-
//All events have been processed on the chain fetchers queue
|
|
319
|
-
//Other chains may be busy syncing
|
|
320
|
-
let hasNoMoreEventsToProcess = cf->ChainFetcher.hasNoMoreEventsToProcess
|
|
321
|
-
|
|
322
|
-
if hasNoMoreEventsToProcess {
|
|
323
|
-
{
|
|
324
|
-
...cf,
|
|
325
|
-
timestampCaughtUpToHeadOrEndblock: Date.make()->Some,
|
|
326
|
-
}
|
|
327
|
-
} else {
|
|
328
|
-
//Default to just returning cf
|
|
329
|
-
cf
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
} else {
|
|
333
|
-
//Default to just returning cf
|
|
334
|
-
cf
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Set envio_progress_ready per-chain when it first becomes ready
|
|
338
|
-
if cf->ChainFetcher.isReady {
|
|
339
|
-
if !(prev->ChainFetcher.isReady) {
|
|
340
|
-
Prometheus.ProgressReady.set(~chainId=chain->ChainMap.Chain.toChainId)
|
|
341
|
-
}
|
|
342
|
-
} else {
|
|
343
|
-
allChainsReady := false
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
cf
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
if allChainsReady.contents {
|
|
350
|
-
Prometheus.ProgressReady.setAllReady()
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
{
|
|
354
|
-
...chainManager,
|
|
355
|
-
chainFetchers,
|
|
356
|
-
isRealtime: chainManager.isRealtime || allChainsReady.contents,
|
|
357
|
-
}
|
|
358
|
-
}
|