envio 3.2.1 → 3.3.0-alpha.0

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.
Files changed (106) hide show
  1. package/package.json +6 -7
  2. package/src/Batch.res +12 -15
  3. package/src/Batch.res.mjs +4 -5
  4. package/src/BatchProcessing.res +199 -0
  5. package/src/BatchProcessing.res.mjs +125 -0
  6. package/src/ChainFetching.res +375 -0
  7. package/src/ChainFetching.res.mjs +206 -0
  8. package/src/ChainMetadata.res +27 -0
  9. package/src/ChainMetadata.res.mjs +27 -0
  10. package/src/ChainState.res +618 -0
  11. package/src/ChainState.res.mjs +461 -0
  12. package/src/ChainState.resi +85 -0
  13. package/src/Config.res +13 -4
  14. package/src/Config.res.mjs +8 -3
  15. package/src/ContractRegisterContext.res +106 -0
  16. package/src/ContractRegisterContext.res.mjs +76 -0
  17. package/src/Core.res +3 -0
  18. package/src/CrossChainState.res +269 -0
  19. package/src/CrossChainState.res.mjs +197 -0
  20. package/src/CrossChainState.resi +47 -0
  21. package/src/Ecosystem.res +58 -0
  22. package/src/Ecosystem.res.mjs +43 -1
  23. package/src/Env.res +7 -2
  24. package/src/Env.res.mjs +5 -2
  25. package/src/EventConfigBuilder.res +2 -2
  26. package/src/EventProcessing.res +60 -46
  27. package/src/EventProcessing.res.mjs +33 -32
  28. package/src/EventUtils.res +0 -4
  29. package/src/EventUtils.res.mjs +0 -4
  30. package/src/ExitOnCaughtUp.res +10 -0
  31. package/src/ExitOnCaughtUp.res.mjs +22 -0
  32. package/src/FetchState.res +124 -62
  33. package/src/FetchState.res.mjs +159 -93
  34. package/src/InMemoryStore.res +36 -451
  35. package/src/InMemoryStore.res.mjs +20 -369
  36. package/src/IndexerLoop.res +44 -0
  37. package/src/IndexerLoop.res.mjs +46 -0
  38. package/src/IndexerState.res +544 -0
  39. package/src/IndexerState.res.mjs +547 -0
  40. package/src/IndexerState.resi +132 -0
  41. package/src/Internal.res +29 -8
  42. package/src/LoadLayer.res +20 -18
  43. package/src/LoadLayer.res.mjs +14 -12
  44. package/src/LoadLayer.resi +6 -3
  45. package/src/Logging.res +11 -44
  46. package/src/Logging.res.mjs +10 -42
  47. package/src/Main.res +54 -79
  48. package/src/Main.res.mjs +44 -56
  49. package/src/PgStorage.res +8 -71
  50. package/src/PgStorage.res.mjs +3 -47
  51. package/src/Prometheus.res +7 -8
  52. package/src/Prometheus.res.mjs +7 -4
  53. package/src/PruneStaleHistory.res +45 -0
  54. package/src/PruneStaleHistory.res.mjs +46 -0
  55. package/src/RawEvent.res +73 -0
  56. package/src/RawEvent.res.mjs +51 -0
  57. package/src/Rollback.res +204 -0
  58. package/src/Rollback.res.mjs +118 -0
  59. package/src/SimulateItems.res +12 -10
  60. package/src/SimulateItems.res.mjs +1 -1
  61. package/src/UserContext.res +26 -114
  62. package/src/UserContext.res.mjs +15 -78
  63. package/src/Writing.res +242 -0
  64. package/src/Writing.res.mjs +215 -0
  65. package/src/db/InternalTable.res +14 -27
  66. package/src/sources/Evm.res +40 -1
  67. package/src/sources/Evm.res.mjs +94 -84
  68. package/src/sources/Fuel.res +40 -1
  69. package/src/sources/Fuel.res.mjs +36 -26
  70. package/src/sources/HyperFuel.res +41 -120
  71. package/src/sources/HyperFuel.res.mjs +42 -80
  72. package/src/sources/HyperFuel.resi +1 -24
  73. package/src/sources/HyperFuelClient.res +16 -297
  74. package/src/sources/HyperFuelClient.res.mjs +5 -4
  75. package/src/sources/HyperFuelSource.res +33 -8
  76. package/src/sources/HyperFuelSource.res.mjs +56 -10
  77. package/src/sources/HyperSyncSource.res +5 -3
  78. package/src/sources/HyperSyncSource.res.mjs +1 -1
  79. package/src/sources/RpcSource.res +2 -2
  80. package/src/sources/RpcSource.res.mjs +1 -1
  81. package/src/sources/SourceManager.res +8 -18
  82. package/src/sources/SourceManager.res.mjs +8 -5
  83. package/src/sources/SourceManager.resi +4 -1
  84. package/src/sources/Svm.res +18 -1
  85. package/src/sources/Svm.res.mjs +30 -22
  86. package/src/sources/SvmHyperSyncSource.res +1 -1
  87. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  88. package/src/tui/Tui.res +38 -36
  89. package/src/tui/Tui.res.mjs +51 -51
  90. package/src/ChainFetcher.res +0 -519
  91. package/src/ChainFetcher.res.mjs +0 -314
  92. package/src/ChainManager.res +0 -358
  93. package/src/ChainManager.res.mjs +0 -291
  94. package/src/Ctx.res +0 -6
  95. package/src/Ctx.res.mjs +0 -2
  96. package/src/GlobalState.res +0 -1056
  97. package/src/GlobalState.res.mjs +0 -1086
  98. package/src/GlobalStateManager.res +0 -57
  99. package/src/GlobalStateManager.res.mjs +0 -68
  100. package/src/GlobalStateManager.resi +0 -7
  101. package/src/Ports.res +0 -5
  102. package/src/Ports.res.mjs +0 -9
  103. package/src/adapters/MarkBatchProcessedAdapter.res +0 -5
  104. package/src/adapters/MarkBatchProcessedAdapter.res.mjs +0 -14
  105. package/src/sources/EnvioApiClient.res +0 -15
  106. package/src/sources/EnvioApiClient.res.mjs +0 -24
@@ -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 */
@@ -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
- }