envio 3.0.0-alpha.2 → 3.0.0-alpha.20

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 (175) hide show
  1. package/README.md +164 -30
  2. package/bin.mjs +49 -0
  3. package/evm.schema.json +79 -169
  4. package/fuel.schema.json +50 -21
  5. package/index.d.ts +497 -1
  6. package/index.js +4 -0
  7. package/package.json +42 -31
  8. package/rescript.json +4 -1
  9. package/src/Batch.res +11 -8
  10. package/src/Batch.res.mjs +11 -9
  11. package/src/ChainFetcher.res +531 -0
  12. package/src/ChainFetcher.res.mjs +339 -0
  13. package/src/ChainManager.res +190 -0
  14. package/src/ChainManager.res.mjs +166 -0
  15. package/src/Change.res +3 -3
  16. package/src/Config.gen.ts +19 -0
  17. package/src/Config.res +737 -22
  18. package/src/Config.res.mjs +703 -26
  19. package/src/{Indexer.res → Ctx.res} +1 -1
  20. package/src/Ecosystem.res +9 -124
  21. package/src/Ecosystem.res.mjs +19 -160
  22. package/src/Env.res +30 -74
  23. package/src/Env.res.mjs +25 -87
  24. package/src/Envio.gen.ts +3 -1
  25. package/src/Envio.res +20 -9
  26. package/src/EventProcessing.res +469 -0
  27. package/src/EventProcessing.res.mjs +337 -0
  28. package/src/EvmTypes.gen.ts +6 -0
  29. package/src/EvmTypes.res +1 -0
  30. package/src/FetchState.res +1256 -639
  31. package/src/FetchState.res.mjs +1135 -612
  32. package/src/GlobalState.res +1190 -0
  33. package/src/GlobalState.res.mjs +1183 -0
  34. package/src/GlobalStateManager.res +68 -0
  35. package/src/GlobalStateManager.res.mjs +75 -0
  36. package/src/GlobalStateManager.resi +7 -0
  37. package/src/HandlerLoader.res +89 -0
  38. package/src/HandlerLoader.res.mjs +79 -0
  39. package/src/HandlerRegister.res +357 -0
  40. package/src/HandlerRegister.res.mjs +299 -0
  41. package/src/{EventRegister.resi → HandlerRegister.resi} +13 -13
  42. package/src/Hasura.res +111 -175
  43. package/src/Hasura.res.mjs +88 -150
  44. package/src/InMemoryStore.res +1 -1
  45. package/src/InMemoryStore.res.mjs +3 -3
  46. package/src/InMemoryTable.res +1 -1
  47. package/src/InMemoryTable.res.mjs +1 -1
  48. package/src/Internal.gen.ts +4 -0
  49. package/src/Internal.res +230 -12
  50. package/src/Internal.res.mjs +115 -1
  51. package/src/LoadLayer.res +444 -0
  52. package/src/LoadLayer.res.mjs +296 -0
  53. package/src/LoadLayer.resi +32 -0
  54. package/src/LogSelection.res +33 -27
  55. package/src/LogSelection.res.mjs +6 -0
  56. package/src/Logging.res +21 -7
  57. package/src/Logging.res.mjs +16 -8
  58. package/src/Main.res +377 -0
  59. package/src/Main.res.mjs +339 -0
  60. package/src/Persistence.res +7 -21
  61. package/src/Persistence.res.mjs +3 -3
  62. package/src/PgStorage.gen.ts +10 -0
  63. package/src/PgStorage.res +116 -69
  64. package/src/PgStorage.res.d.mts +5 -0
  65. package/src/PgStorage.res.mjs +93 -50
  66. package/src/Prometheus.res +294 -224
  67. package/src/Prometheus.res.mjs +353 -340
  68. package/src/ReorgDetection.res +6 -10
  69. package/src/ReorgDetection.res.mjs +6 -6
  70. package/src/SafeCheckpointTracking.res +4 -4
  71. package/src/SafeCheckpointTracking.res.mjs +2 -2
  72. package/src/Sink.res +4 -2
  73. package/src/Sink.res.mjs +2 -1
  74. package/src/TableIndices.res +0 -1
  75. package/src/TestIndexer.res +692 -0
  76. package/src/TestIndexer.res.mjs +527 -0
  77. package/src/TestIndexerProxyStorage.res +205 -0
  78. package/src/TestIndexerProxyStorage.res.mjs +151 -0
  79. package/src/TopicFilter.res +1 -1
  80. package/src/Types.ts +1 -1
  81. package/src/UserContext.res +424 -0
  82. package/src/UserContext.res.mjs +279 -0
  83. package/src/Utils.res +97 -26
  84. package/src/Utils.res.mjs +91 -44
  85. package/src/bindings/BigInt.res +10 -0
  86. package/src/bindings/BigInt.res.mjs +15 -0
  87. package/src/bindings/ClickHouse.res +120 -23
  88. package/src/bindings/ClickHouse.res.mjs +118 -28
  89. package/src/bindings/DateFns.res +74 -0
  90. package/src/bindings/DateFns.res.mjs +22 -0
  91. package/src/bindings/EventSource.res +8 -1
  92. package/src/bindings/EventSource.res.mjs +8 -1
  93. package/src/bindings/Express.res +1 -0
  94. package/src/bindings/Hrtime.res +14 -1
  95. package/src/bindings/Hrtime.res.mjs +22 -2
  96. package/src/bindings/Hrtime.resi +4 -0
  97. package/src/bindings/Lodash.res +0 -1
  98. package/src/bindings/NodeJs.res +49 -3
  99. package/src/bindings/NodeJs.res.mjs +11 -3
  100. package/src/bindings/Pino.res +24 -10
  101. package/src/bindings/Pino.res.mjs +14 -8
  102. package/src/bindings/Postgres.gen.ts +8 -0
  103. package/src/bindings/Postgres.res +5 -1
  104. package/src/bindings/Postgres.res.d.mts +5 -0
  105. package/src/bindings/PromClient.res +0 -10
  106. package/src/bindings/PromClient.res.mjs +0 -3
  107. package/src/bindings/Vitest.res +142 -0
  108. package/src/bindings/Vitest.res.mjs +9 -0
  109. package/src/bindings/WebSocket.res +27 -0
  110. package/src/bindings/WebSocket.res.mjs +2 -0
  111. package/src/bindings/Yargs.res +8 -0
  112. package/src/bindings/Yargs.res.mjs +2 -0
  113. package/src/db/EntityHistory.res +7 -7
  114. package/src/db/EntityHistory.res.mjs +9 -9
  115. package/src/db/InternalTable.res +59 -111
  116. package/src/db/InternalTable.res.mjs +73 -104
  117. package/src/db/Table.res +27 -8
  118. package/src/db/Table.res.mjs +25 -14
  119. package/src/sources/Evm.res +84 -0
  120. package/src/sources/Evm.res.mjs +105 -0
  121. package/src/sources/EvmChain.res +94 -0
  122. package/src/sources/EvmChain.res.mjs +60 -0
  123. package/src/sources/Fuel.res +19 -34
  124. package/src/sources/Fuel.res.mjs +34 -16
  125. package/src/sources/FuelSDK.res +38 -0
  126. package/src/sources/FuelSDK.res.mjs +29 -0
  127. package/src/sources/HyperFuel.res +2 -2
  128. package/src/sources/HyperFuel.resi +1 -1
  129. package/src/sources/HyperFuelClient.res +2 -2
  130. package/src/sources/HyperFuelSource.res +33 -13
  131. package/src/sources/HyperFuelSource.res.mjs +24 -16
  132. package/src/sources/HyperSync.res +36 -6
  133. package/src/sources/HyperSync.res.mjs +9 -7
  134. package/src/sources/HyperSync.resi +4 -0
  135. package/src/sources/HyperSyncClient.res +1 -1
  136. package/src/sources/HyperSyncHeightStream.res +47 -116
  137. package/src/sources/HyperSyncHeightStream.res.mjs +46 -73
  138. package/src/sources/HyperSyncSource.res +118 -139
  139. package/src/sources/HyperSyncSource.res.mjs +104 -121
  140. package/src/sources/Rpc.res +86 -14
  141. package/src/sources/Rpc.res.mjs +101 -9
  142. package/src/sources/RpcSource.res +621 -364
  143. package/src/sources/RpcSource.res.mjs +843 -410
  144. package/src/sources/RpcWebSocketHeightStream.res +181 -0
  145. package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
  146. package/src/sources/Source.res +7 -5
  147. package/src/sources/SourceManager.res +325 -225
  148. package/src/sources/SourceManager.res.mjs +314 -171
  149. package/src/sources/SourceManager.resi +17 -6
  150. package/src/sources/Svm.res +81 -0
  151. package/src/sources/Svm.res.mjs +90 -0
  152. package/src/tui/Tui.res +247 -0
  153. package/src/tui/Tui.res.mjs +337 -0
  154. package/src/tui/bindings/Ink.res +371 -0
  155. package/src/tui/bindings/Ink.res.mjs +72 -0
  156. package/src/tui/bindings/Style.res +123 -0
  157. package/src/tui/bindings/Style.res.mjs +2 -0
  158. package/src/tui/components/BufferedProgressBar.res +40 -0
  159. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  160. package/src/tui/components/CustomHooks.res +122 -0
  161. package/src/tui/components/CustomHooks.res.mjs +179 -0
  162. package/src/tui/components/Messages.res +41 -0
  163. package/src/tui/components/Messages.res.mjs +75 -0
  164. package/src/tui/components/SyncETA.res +174 -0
  165. package/src/tui/components/SyncETA.res.mjs +263 -0
  166. package/src/tui/components/TuiData.res +47 -0
  167. package/src/tui/components/TuiData.res.mjs +34 -0
  168. package/svm.schema.json +112 -0
  169. package/bin.js +0 -48
  170. package/src/EventRegister.res +0 -241
  171. package/src/EventRegister.res.mjs +0 -240
  172. package/src/bindings/Ethers.gen.ts +0 -14
  173. package/src/bindings/Ethers.res +0 -204
  174. package/src/bindings/Ethers.res.mjs +0 -130
  175. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
@@ -0,0 +1,339 @@
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 Caml from "rescript/lib/es6/caml.js";
6
+ import * as Utils from "./Utils.res.mjs";
7
+ import * as Js_exn from "rescript/lib/es6/js_exn.js";
8
+ import * as Logging from "./Logging.res.mjs";
9
+ import * as $$Promise from "./bindings/Promise.res.mjs";
10
+ import * as ChainMap from "./ChainMap.res.mjs";
11
+ import * as EvmChain from "./sources/EvmChain.res.mjs";
12
+ import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
13
+ import * as FetchState from "./FetchState.res.mjs";
14
+ import * as Prometheus from "./Prometheus.res.mjs";
15
+ import * as Belt_Option from "rescript/lib/es6/belt_Option.js";
16
+ import * as Caml_option from "rescript/lib/es6/caml_option.js";
17
+ import * as EventRouter from "./sources/EventRouter.res.mjs";
18
+ import * as UserContext from "./UserContext.res.mjs";
19
+ import * as ErrorHandling from "./ErrorHandling.res.mjs";
20
+ import * as SourceManager from "./sources/SourceManager.res.mjs";
21
+ import * as ReorgDetection from "./ReorgDetection.res.mjs";
22
+ import * as HyperFuelSource from "./sources/HyperFuelSource.res.mjs";
23
+ import * as Caml_js_exceptions from "rescript/lib/es6/caml_js_exceptions.js";
24
+ import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
25
+
26
+ function make(chainConfig, dynamicContracts, startBlock, endBlock, firstEventBlockOpt, progressBlockNumber, config, registrations, targetBufferSize, logger, timestampCaughtUpToHeadOrEndblock, numEventsProcessed, isInReorgThreshold, reorgCheckpoints, maxReorgDepth, knownHeightOpt) {
27
+ var firstEventBlock = firstEventBlockOpt !== undefined ? Caml_option.valFromOption(firstEventBlockOpt) : undefined;
28
+ var knownHeight = knownHeightOpt !== undefined ? knownHeightOpt : 0;
29
+ var eventRouter = EventRouter.empty();
30
+ var contracts = [];
31
+ var eventConfigs = [];
32
+ var notRegisteredEvents = [];
33
+ Belt_Array.forEach(chainConfig.contracts, (function (contract) {
34
+ var contractName = contract.name;
35
+ Belt_Array.forEach(contract.events, (function (eventConfig) {
36
+ var hasContractRegister = Belt_Option.isSome(eventConfig.contractRegister);
37
+ EventRouter.addOrThrow(eventRouter, eventConfig.id, undefined, contractName, eventConfig.isWildcard, eventConfig.name, ChainMap.Chain.makeUnsafe(chainConfig.id));
38
+ var shouldBeIncluded;
39
+ if (config.enableRawEvents) {
40
+ shouldBeIncluded = true;
41
+ } else {
42
+ var isRegistered = hasContractRegister || Belt_Option.isSome(eventConfig.handler);
43
+ if (!isRegistered) {
44
+ notRegisteredEvents.push(eventConfig);
45
+ }
46
+ shouldBeIncluded = isRegistered;
47
+ }
48
+ var shouldSkip;
49
+ try {
50
+ var getEventFiltersOrThrow = eventConfig.getEventFiltersOrThrow;
51
+ if (getEventFiltersOrThrow) {
52
+ var match = getEventFiltersOrThrow(ChainMap.Chain.makeUnsafe(chainConfig.id));
53
+ shouldSkip = match.TAG === "Static" ? match._0.length === 0 : false;
54
+ } else {
55
+ shouldSkip = false;
56
+ }
57
+ }
58
+ catch (exn){
59
+ shouldSkip = false;
60
+ }
61
+ if (shouldBeIncluded && !shouldSkip) {
62
+ eventConfigs.push(eventConfig);
63
+ return ;
64
+ }
65
+
66
+ }));
67
+ var startBlock = contract.startBlock;
68
+ if (startBlock !== undefined && startBlock < chainConfig.startBlock) {
69
+ Js_exn.raiseError("The start block for contract \"" + contractName + "\" is less than the chain start block. This is not supported yet.");
70
+ }
71
+ Belt_Array.forEach(contract.addresses, (function (address) {
72
+ var startBlock = contract.startBlock;
73
+ contracts.push({
74
+ address: address,
75
+ contractName: contract.name,
76
+ startBlock: startBlock !== undefined ? startBlock : chainConfig.startBlock,
77
+ registrationBlock: undefined
78
+ });
79
+ }));
80
+ }));
81
+ Belt_Array.forEach(dynamicContracts, (function (dc) {
82
+ contracts.push(dc);
83
+ }));
84
+ if (Utils.$$Array.notEmpty(notRegisteredEvents)) {
85
+ Logging.childInfo(logger, "The event" + (
86
+ notRegisteredEvents.length > 1 ? "s" : ""
87
+ ) + " " + Belt_Array.map(notRegisteredEvents, (function (eventConfig) {
88
+ return eventConfig.contractName + "." + eventConfig.name;
89
+ })).join(", ") + " don't have an event handler and skipped for indexing.");
90
+ }
91
+ var onBlockConfigs = registrations.onBlockByChainId[String(chainConfig.id)];
92
+ if (onBlockConfigs !== undefined) {
93
+ Belt_Array.forEach(onBlockConfigs, (function (onBlockConfig) {
94
+ if (Belt_Option.getWithDefault(onBlockConfig.startBlock, startBlock) < startBlock) {
95
+ Js_exn.raiseError("The start block for onBlock handler \"" + onBlockConfig.name + "\" is less than the chain start block (" + String(startBlock) + "). This is not supported yet.");
96
+ }
97
+ if (endBlock !== undefined && Belt_Option.getWithDefault(onBlockConfig.endBlock, endBlock) > endBlock) {
98
+ return Js_exn.raiseError("The end block for onBlock handler \"" + onBlockConfig.name + "\" is greater than the chain end block (" + String(endBlock) + "). This is not supported yet.");
99
+ }
100
+
101
+ }));
102
+ }
103
+ var fetchState = FetchState.make(startBlock, endBlock, eventConfigs, contracts, config.maxAddrInPartition, chainConfig.id, targetBufferSize, knownHeight, progressBlockNumber, onBlockConfigs, Caml.int_max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth, chainConfig.blockLag), Caml_option.some(firstEventBlock));
104
+ var chainReorgCheckpoints = Belt_Array.keepMapU(reorgCheckpoints, (function (reorgCheckpoint) {
105
+ if (reorgCheckpoint.chain_id === chainConfig.id) {
106
+ return reorgCheckpoint;
107
+ }
108
+
109
+ }));
110
+ var chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
111
+ var lowercaseAddresses = config.lowercaseAddresses;
112
+ var sources = chainConfig.sourceConfig;
113
+ var sources$1;
114
+ switch (sources.TAG) {
115
+ case "EvmSourceConfig" :
116
+ var evmContracts = Belt_Array.map(chainConfig.contracts, (function (contract) {
117
+ return {
118
+ name: contract.name,
119
+ abi: contract.abi,
120
+ events: contract.events
121
+ };
122
+ }));
123
+ var allEventSignatures = Belt_Array.flatMap(chainConfig.contracts, (function (contract) {
124
+ return contract.eventSignatures;
125
+ }));
126
+ var evmRpcs = Belt_Array.map(sources.rpcs, (function (rpc) {
127
+ var syncConfig = rpc.syncConfig;
128
+ var ws = rpc.ws;
129
+ return {
130
+ url: rpc.url,
131
+ sourceFor: rpc.sourceFor,
132
+ syncConfig: syncConfig,
133
+ ws: ws
134
+ };
135
+ }));
136
+ sources$1 = EvmChain.makeSources(chain, evmContracts, sources.hypersync, allEventSignatures, evmRpcs, lowercaseAddresses);
137
+ break;
138
+ case "FuelSourceConfig" :
139
+ sources$1 = [HyperFuelSource.make({
140
+ chain: chain,
141
+ endpointUrl: sources.hypersync
142
+ })];
143
+ break;
144
+ case "SvmSourceConfig" :
145
+ sources$1 = [Svm.makeRPCSource(chain, sources.rpc)];
146
+ break;
147
+ case "CustomSources" :
148
+ sources$1 = sources._0;
149
+ break;
150
+
151
+ }
152
+ return {
153
+ logger: logger,
154
+ fetchState: fetchState,
155
+ sourceManager: SourceManager.make(sources$1, Env.maxPartitionConcurrency, Belt_Option.isSome(timestampCaughtUpToHeadOrEndblock), undefined, undefined, undefined, undefined, undefined),
156
+ chainConfig: chainConfig,
157
+ isProgressAtHead: false,
158
+ timestampCaughtUpToHeadOrEndblock: timestampCaughtUpToHeadOrEndblock,
159
+ committedProgressBlockNumber: progressBlockNumber,
160
+ numEventsProcessed: numEventsProcessed,
161
+ reorgDetection: ReorgDetection.make(chainReorgCheckpoints, maxReorgDepth, config.shouldRollbackOnReorg),
162
+ safeCheckpointTracking: SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)
163
+ };
164
+ }
165
+
166
+ function makeFromConfig(chainConfig, config, registrations, targetBufferSize, knownHeight) {
167
+ var logger = Logging.createChild({
168
+ chainId: chainConfig.id
169
+ });
170
+ return make(chainConfig, [], chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrations, targetBufferSize, logger, undefined, 0, false, [], chainConfig.maxReorgDepth, knownHeight);
171
+ }
172
+
173
+ async function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, config, registrations, targetBufferSize) {
174
+ var chainId = chainConfig.id;
175
+ var logger = Logging.createChild({
176
+ chainId: chainId
177
+ });
178
+ Prometheus.ProgressEventsCount.set(resumedChainState.numEventsProcessed, chainId);
179
+ var progressBlockNumber = resumedChainState.progressBlockNumber >= 0 ? resumedChainState.progressBlockNumber : resumedChainState.startBlock - 1 | 0;
180
+ return make(chainConfig, resumedChainState.dynamicContracts, resumedChainState.startBlock, resumedChainState.endBlock, Caml_option.some(resumedChainState.firstEventBlockNumber), progressBlockNumber, config, registrations, targetBufferSize, logger, Env.updateSyncTimeOnRestart ? undefined : resumedChainState.timestampCaughtUpToHeadOrEndblock, resumedChainState.numEventsProcessed, isInReorgThreshold, reorgCheckpoints, resumedChainState.maxReorgDepth, resumedChainState.sourceBlockNumber);
181
+ }
182
+
183
+ function getContractStartBlock(config, chain, contractName) {
184
+ var chainConfig = ChainMap.get(config.chainMap, chain);
185
+ return Belt_Option.flatMap(Caml_option.undefined_to_opt(chainConfig.contracts.find(function (contract) {
186
+ return contract.name === contractName;
187
+ })), (function (contract) {
188
+ return contract.startBlock;
189
+ }));
190
+ }
191
+
192
+ async function runContractRegistersOrThrow(itemsWithContractRegister, chain, config) {
193
+ var itemsWithDcs = [];
194
+ var onRegister = function (item, contractAddress, contractName) {
195
+ var blockNumber = item.blockNumber;
196
+ var configuredStartBlock = getContractStartBlock(config, chain, contractName);
197
+ var contractStartBlock = configuredStartBlock !== undefined ? configuredStartBlock : blockNumber;
198
+ var dc_registrationBlock = blockNumber;
199
+ var dc = {
200
+ address: contractAddress,
201
+ contractName: contractName,
202
+ startBlock: contractStartBlock,
203
+ registrationBlock: dc_registrationBlock
204
+ };
205
+ var dcs = item.dcs;
206
+ if (dcs !== undefined) {
207
+ dcs.push(dc);
208
+ } else {
209
+ item.dcs = [dc];
210
+ itemsWithDcs.push(item);
211
+ }
212
+ };
213
+ var promises = [];
214
+ for(var idx = 0 ,idx_finish = itemsWithContractRegister.length; idx < idx_finish; ++idx){
215
+ var item = itemsWithContractRegister[idx];
216
+ var match = item.eventConfig;
217
+ var contractRegister = match.contractRegister;
218
+ var contractRegister$1 = contractRegister !== undefined ? contractRegister : Js_exn.raiseError("Contract register is not set for event " + match.name);
219
+ var errorMessage = "Event contractRegister failed, please fix the error to keep the indexer running smoothly";
220
+ try {
221
+ var params = {
222
+ item: item,
223
+ onRegister: onRegister,
224
+ config: config,
225
+ isResolved: false
226
+ };
227
+ var result = contractRegister$1(UserContext.getContractRegisterArgs(params));
228
+ if ($$Promise.isCatchable(result)) {
229
+ promises.push($$Promise.$$catch(result.then((function(params){
230
+ return function (r) {
231
+ params.isResolved = true;
232
+
233
+ }
234
+ }(params))), (function(item,params){
235
+ return function (exn) {
236
+ params.isResolved = true;
237
+ return ErrorHandling.mkLogAndRaise(Logging.getItemLogger(item), errorMessage, exn);
238
+ }
239
+ }(item,params))));
240
+ } else {
241
+ params.isResolved = true;
242
+ }
243
+ }
244
+ catch (raw_exn){
245
+ var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
246
+ ErrorHandling.mkLogAndRaise(Logging.getItemLogger(item), errorMessage, exn);
247
+ }
248
+ }
249
+ if (Utils.$$Array.notEmpty(promises)) {
250
+ await Promise.all(promises);
251
+ }
252
+ return itemsWithDcs;
253
+ }
254
+
255
+ function handleQueryResult(chainFetcher, query, newItems, newItemsWithDcs, latestFetchedBlock, knownHeight) {
256
+ var fs = newItemsWithDcs.length !== 0 ? FetchState.registerDynamicContracts(chainFetcher.fetchState, newItemsWithDcs) : chainFetcher.fetchState;
257
+ return {
258
+ logger: chainFetcher.logger,
259
+ fetchState: FetchState.updateKnownHeight(FetchState.handleQueryResult(fs, query, latestFetchedBlock, newItems), knownHeight),
260
+ sourceManager: chainFetcher.sourceManager,
261
+ chainConfig: chainFetcher.chainConfig,
262
+ isProgressAtHead: chainFetcher.isProgressAtHead,
263
+ timestampCaughtUpToHeadOrEndblock: chainFetcher.timestampCaughtUpToHeadOrEndblock,
264
+ committedProgressBlockNumber: chainFetcher.committedProgressBlockNumber,
265
+ numEventsProcessed: chainFetcher.numEventsProcessed,
266
+ reorgDetection: chainFetcher.reorgDetection,
267
+ safeCheckpointTracking: chainFetcher.safeCheckpointTracking
268
+ };
269
+ }
270
+
271
+ function hasProcessedToEndblock(self) {
272
+ var endBlock = self.fetchState.endBlock;
273
+ if (endBlock !== undefined) {
274
+ return self.committedProgressBlockNumber >= endBlock;
275
+ } else {
276
+ return false;
277
+ }
278
+ }
279
+
280
+ function hasNoMoreEventsToProcess(self) {
281
+ return FetchState.bufferSize(self.fetchState) === 0;
282
+ }
283
+
284
+ function getHighestBlockBelowThreshold(cf) {
285
+ var highestBlockBelowThreshold = cf.fetchState.knownHeight - cf.chainConfig.maxReorgDepth | 0;
286
+ if (highestBlockBelowThreshold < 0) {
287
+ return 0;
288
+ } else {
289
+ return highestBlockBelowThreshold;
290
+ }
291
+ }
292
+
293
+ async function getLastKnownValidBlock(chainFetcher, reorgBlockNumber, getBlockHashesOpt) {
294
+ var getBlockHashes = getBlockHashesOpt !== undefined ? getBlockHashesOpt : SourceManager.getActiveSource(chainFetcher.sourceManager).getBlockHashes;
295
+ var scannedBlockNumbers = ReorgDetection.getThresholdBlockNumbersBelowBlock(chainFetcher.reorgDetection, reorgBlockNumber, chainFetcher.fetchState.knownHeight);
296
+ var getBlockHashes$1 = function (blockNumbers) {
297
+ return getBlockHashes(blockNumbers, chainFetcher.logger).then(function (res) {
298
+ if (res.TAG === "Ok") {
299
+ return res._0;
300
+ } else {
301
+ return ErrorHandling.mkLogAndRaise(undefined, "Failed to fetch blockHashes for given blockNumbers during rollback", res._0);
302
+ }
303
+ });
304
+ };
305
+ if (scannedBlockNumbers.length === 0) {
306
+ return getHighestBlockBelowThreshold(chainFetcher);
307
+ }
308
+ var blockNumbersAndHashes = await getBlockHashes$1(scannedBlockNumbers);
309
+ var blockNumber = ReorgDetection.getLatestValidScannedBlock(chainFetcher.reorgDetection, blockNumbersAndHashes);
310
+ if (blockNumber !== undefined) {
311
+ return blockNumber;
312
+ } else {
313
+ return getHighestBlockBelowThreshold(chainFetcher);
314
+ }
315
+ }
316
+
317
+ function isActivelyIndexing(chainFetcher) {
318
+ return FetchState.isActivelyIndexing(chainFetcher.fetchState);
319
+ }
320
+
321
+ function isReady(chainFetcher) {
322
+ return chainFetcher.timestampCaughtUpToHeadOrEndblock !== undefined;
323
+ }
324
+
325
+ export {
326
+ make ,
327
+ makeFromConfig ,
328
+ makeFromDbState ,
329
+ getContractStartBlock ,
330
+ runContractRegistersOrThrow ,
331
+ handleQueryResult ,
332
+ hasProcessedToEndblock ,
333
+ hasNoMoreEventsToProcess ,
334
+ getHighestBlockBelowThreshold ,
335
+ getLastKnownValidBlock ,
336
+ isActivelyIndexing ,
337
+ isReady ,
338
+ }
339
+ /* Env Not a pure module */
@@ -0,0 +1,190 @@
1
+ open Belt
2
+
3
+ type t = {
4
+ committedCheckpointId: bigint,
5
+ chainFetchers: ChainMap.t<ChainFetcher.t>,
6
+ multichain: Config.multichain,
7
+ isInReorgThreshold: bool,
8
+ }
9
+
10
+ // Check if progress is past the reorg threshold (safe block).
11
+ // A chain is in reorg threshold when progressBlockNumber > sourceBlockNumber - maxReorgDepth.
12
+ // This matches the logic in InternalTable.Checkpoints.makeGetReorgCheckpointsQuery.
13
+ let isProgressInReorgThreshold = (~progressBlockNumber, ~sourceBlockNumber, ~maxReorgDepth) => {
14
+ maxReorgDepth > 0 &&
15
+ sourceBlockNumber > 0 &&
16
+ progressBlockNumber > sourceBlockNumber - maxReorgDepth
17
+ }
18
+
19
+ let calculateTargetBufferSize = (~activeChainsCount) => {
20
+ switch Env.targetBufferSize {
21
+ | Some(size) => size
22
+ | None =>
23
+ switch activeChainsCount {
24
+ | 1 => 60_000
25
+ | 2 => 30_000
26
+ | 3 => 20_000
27
+ | 4 => 15_000
28
+ | 5 => 10_000
29
+ | _ => 5_000
30
+ }
31
+ }
32
+ }
33
+
34
+ let makeFromDbState = async (
35
+ ~initialState: Persistence.initialState,
36
+ ~config: Config.t,
37
+ ~registrations,
38
+ ): t => {
39
+ let isInReorgThreshold = if initialState.cleanRun {
40
+ false
41
+ } else {
42
+ // Check if any chain is in reorg threshold by comparing progress with sourceBlock - maxReorgDepth.
43
+ initialState.chains->Array.some(chain =>
44
+ isProgressInReorgThreshold(
45
+ ~progressBlockNumber=chain.progressBlockNumber,
46
+ ~sourceBlockNumber=chain.sourceBlockNumber,
47
+ ~maxReorgDepth=chain.maxReorgDepth,
48
+ )
49
+ )
50
+ }
51
+
52
+ let targetBufferSize = calculateTargetBufferSize(
53
+ ~activeChainsCount=initialState.chains->Array.length,
54
+ )
55
+ Prometheus.ProcessingMaxBatchSize.set(~maxBatchSize=config.batchSize)
56
+ Prometheus.IndexingTargetBufferSize.set(~targetBufferSize)
57
+ Prometheus.ReorgThreshold.set(~isInReorgThreshold)
58
+ initialState.cache->Utils.Dict.forEach(({effectName, count}) => {
59
+ Prometheus.EffectCacheCount.set(~count, ~effectName)
60
+ })
61
+
62
+ let chainFetchersArr =
63
+ await initialState.chains
64
+ ->Array.map(async (resumedChainState: Persistence.initialChainState) => {
65
+ let chain = Config.getChain(config, ~chainId=resumedChainState.id)
66
+ let chainConfig = config.chainMap->ChainMap.get(chain)
67
+
68
+ (
69
+ chain,
70
+ await chainConfig->ChainFetcher.makeFromDbState(
71
+ ~resumedChainState,
72
+ ~reorgCheckpoints=initialState.reorgCheckpoints,
73
+ ~isInReorgThreshold,
74
+ ~targetBufferSize,
75
+ ~config,
76
+ ~registrations,
77
+ ),
78
+ )
79
+ })
80
+ ->Promise.all
81
+
82
+ let chainFetchers = ChainMap.fromArrayUnsafe(chainFetchersArr)
83
+
84
+ // Set initial progress metrics from DB state so dashboards reflect
85
+ // the persisted state immediately on restart
86
+ let allChainsReady = ref(chainFetchersArr->Array.length > 0)
87
+ chainFetchersArr->Array.forEach(((chain, cf)) => {
88
+ let chainId = chain->ChainMap.Chain.toChainId
89
+ Prometheus.ProgressBlockNumber.set(~blockNumber=cf.committedProgressBlockNumber, ~chainId)
90
+ Prometheus.ProgressReady.init(~chainId)
91
+ if cf->ChainFetcher.isReady {
92
+ Prometheus.ProgressReady.set(~chainId)
93
+ } else {
94
+ allChainsReady := false
95
+ }
96
+ })
97
+ if allChainsReady.contents {
98
+ Prometheus.ProgressReady.setAllReady()
99
+ }
100
+
101
+ {
102
+ committedCheckpointId: initialState.checkpointId,
103
+ multichain: config.multichain,
104
+ chainFetchers,
105
+ isInReorgThreshold,
106
+ }
107
+ }
108
+
109
+ let getChainFetcher = (chainManager: t, ~chain: ChainMap.Chain.t): ChainFetcher.t => {
110
+ chainManager.chainFetchers->ChainMap.get(chain)
111
+ }
112
+
113
+ let setChainFetcher = (chainManager: t, chainFetcher: ChainFetcher.t) => {
114
+ {
115
+ ...chainManager,
116
+ chainFetchers: chainManager.chainFetchers->ChainMap.set(
117
+ ChainMap.Chain.makeUnsafe(~chainId=chainFetcher.chainConfig.id),
118
+ chainFetcher,
119
+ ),
120
+ }
121
+ }
122
+
123
+ let nextItemIsNone = (chainManager: t): bool => {
124
+ !Batch.hasMultichainReadyItem(
125
+ chainManager.chainFetchers->ChainMap.map(cf => {
126
+ cf.fetchState
127
+ }),
128
+ ~multichain=chainManager.multichain,
129
+ )
130
+ }
131
+
132
+ let createBatch = (chainManager: t, ~batchSizeTarget: int, ~isRollback: bool): Batch.t => {
133
+ Batch.make(
134
+ ~checkpointIdBeforeBatch=chainManager.committedCheckpointId->BigInt.add(
135
+ // Since for rollback we have a diff checkpoint id.
136
+ // This is needed to currectly overwrite old state
137
+ // in an append-only ClickHouse insert.
138
+ isRollback ? 1n : 0n
139
+ ),
140
+ ~chainsBeforeBatch=chainManager.chainFetchers->ChainMap.map((cf): Batch.chainBeforeBatch => {
141
+ fetchState: cf.fetchState,
142
+ progressBlockNumber: cf.committedProgressBlockNumber,
143
+ totalEventsProcessed: cf.numEventsProcessed,
144
+ sourceBlockNumber: cf.fetchState.knownHeight,
145
+ reorgDetection: cf.reorgDetection,
146
+ chainConfig: cf.chainConfig,
147
+ }),
148
+ ~multichain=chainManager.multichain,
149
+ ~batchSizeTarget,
150
+ )
151
+ }
152
+
153
+ let isProgressAtHead = chainManager =>
154
+ chainManager.chainFetchers
155
+ ->ChainMap.values
156
+ ->Js.Array2.every(cf => cf.isProgressAtHead)
157
+
158
+ let isActivelyIndexing = chainManager =>
159
+ chainManager.chainFetchers
160
+ ->ChainMap.values
161
+ ->Js.Array2.every(ChainFetcher.isActivelyIndexing)
162
+
163
+ let getSafeCheckpointId = (chainManager: t) => {
164
+ let chainFetchers = chainManager.chainFetchers->ChainMap.values
165
+
166
+ let result: ref<option<bigint>> = ref(None)
167
+
168
+ for idx in 0 to chainFetchers->Array.length - 1 {
169
+ let chainFetcher = chainFetchers->Array.getUnsafe(idx)
170
+ switch chainFetcher.safeCheckpointTracking {
171
+ | None => () // Skip chains with maxReorgDepth = 0
172
+ | Some(safeCheckpointTracking) => {
173
+ let safeCheckpointId =
174
+ safeCheckpointTracking->SafeCheckpointTracking.getSafeCheckpointId(
175
+ ~sourceBlockNumber=chainFetcher.fetchState.knownHeight,
176
+ )
177
+ switch result.contents {
178
+ | None => result := Some(safeCheckpointId)
179
+ | Some(current) if safeCheckpointId < current => result := Some(safeCheckpointId)
180
+ | _ => ()
181
+ }
182
+ }
183
+ }
184
+ }
185
+
186
+ switch result.contents {
187
+ | Some(id) if id > 0n => Some(id)
188
+ | _ => None // No safe checkpoint found
189
+ }
190
+ }
@@ -0,0 +1,166 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Env from "./Env.res.mjs";
4
+ import * as Batch from "./Batch.res.mjs";
5
+ import * as Utils from "./Utils.res.mjs";
6
+ import * as $$BigInt from "./bindings/BigInt.res.mjs";
7
+ import * as Config from "./Config.res.mjs";
8
+ import * as ChainMap from "./ChainMap.res.mjs";
9
+ import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
10
+ import * as Prometheus from "./Prometheus.res.mjs";
11
+ import * as ChainFetcher from "./ChainFetcher.res.mjs";
12
+ import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
13
+
14
+ function isProgressInReorgThreshold(progressBlockNumber, sourceBlockNumber, maxReorgDepth) {
15
+ if (maxReorgDepth > 0 && sourceBlockNumber > 0) {
16
+ return progressBlockNumber > (sourceBlockNumber - maxReorgDepth | 0);
17
+ } else {
18
+ return false;
19
+ }
20
+ }
21
+
22
+ function calculateTargetBufferSize(activeChainsCount) {
23
+ if (Env.targetBufferSize !== undefined) {
24
+ return Env.targetBufferSize;
25
+ }
26
+ switch (activeChainsCount) {
27
+ case 1 :
28
+ return 60000;
29
+ case 2 :
30
+ return 30000;
31
+ case 3 :
32
+ return 20000;
33
+ case 4 :
34
+ return 15000;
35
+ case 5 :
36
+ return 10000;
37
+ default:
38
+ return 5000;
39
+ }
40
+ }
41
+
42
+ async function makeFromDbState(initialState, config, registrations) {
43
+ var isInReorgThreshold = initialState.cleanRun ? false : Belt_Array.some(initialState.chains, (function (chain) {
44
+ return isProgressInReorgThreshold(chain.progressBlockNumber, chain.sourceBlockNumber, chain.maxReorgDepth);
45
+ }));
46
+ var targetBufferSize = calculateTargetBufferSize(initialState.chains.length);
47
+ Prometheus.ProcessingMaxBatchSize.set(config.batchSize);
48
+ Prometheus.IndexingTargetBufferSize.set(targetBufferSize);
49
+ Prometheus.ReorgThreshold.set(isInReorgThreshold);
50
+ Utils.Dict.forEach(initialState.cache, (function (param) {
51
+ var count = param.count;
52
+ Prometheus.EffectCacheCount.set(count, param.effectName);
53
+ }));
54
+ var chainFetchersArr = await Promise.all(Belt_Array.map(initialState.chains, (async function (resumedChainState) {
55
+ var chain = Config.getChain(config, resumedChainState.id);
56
+ var chainConfig = ChainMap.get(config.chainMap, chain);
57
+ return [
58
+ chain,
59
+ await ChainFetcher.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, config, registrations, targetBufferSize)
60
+ ];
61
+ })));
62
+ var chainFetchers = ChainMap.fromArrayUnsafe(chainFetchersArr);
63
+ var allChainsReady = {
64
+ contents: chainFetchersArr.length !== 0
65
+ };
66
+ Belt_Array.forEach(chainFetchersArr, (function (param) {
67
+ var cf = param[1];
68
+ var chain = param[0];
69
+ Prometheus.ProgressBlockNumber.set(cf.committedProgressBlockNumber, chain);
70
+ Prometheus.ProgressReady.init(chain);
71
+ if (ChainFetcher.isReady(cf)) {
72
+ return Prometheus.ProgressReady.set(chain);
73
+ } else {
74
+ allChainsReady.contents = false;
75
+ return ;
76
+ }
77
+ }));
78
+ if (allChainsReady.contents) {
79
+ Prometheus.ProgressReady.setAllReady();
80
+ }
81
+ return {
82
+ committedCheckpointId: initialState.checkpointId,
83
+ chainFetchers: chainFetchers,
84
+ multichain: config.multichain,
85
+ isInReorgThreshold: isInReorgThreshold
86
+ };
87
+ }
88
+
89
+ function getChainFetcher(chainManager, chain) {
90
+ return ChainMap.get(chainManager.chainFetchers, chain);
91
+ }
92
+
93
+ function setChainFetcher(chainManager, chainFetcher) {
94
+ return {
95
+ committedCheckpointId: chainManager.committedCheckpointId,
96
+ chainFetchers: ChainMap.set(chainManager.chainFetchers, ChainMap.Chain.makeUnsafe(chainFetcher.chainConfig.id), chainFetcher),
97
+ multichain: chainManager.multichain,
98
+ isInReorgThreshold: chainManager.isInReorgThreshold
99
+ };
100
+ }
101
+
102
+ function nextItemIsNone(chainManager) {
103
+ return !Batch.hasMultichainReadyItem(ChainMap.map(chainManager.chainFetchers, (function (cf) {
104
+ return cf.fetchState;
105
+ })), chainManager.multichain);
106
+ }
107
+
108
+ function createBatch(chainManager, batchSizeTarget, isRollback) {
109
+ return Batch.make($$BigInt.add(chainManager.committedCheckpointId, isRollback ? 1n : 0n), ChainMap.map(chainManager.chainFetchers, (function (cf) {
110
+ return {
111
+ fetchState: cf.fetchState,
112
+ reorgDetection: cf.reorgDetection,
113
+ progressBlockNumber: cf.committedProgressBlockNumber,
114
+ sourceBlockNumber: cf.fetchState.knownHeight,
115
+ totalEventsProcessed: cf.numEventsProcessed,
116
+ chainConfig: cf.chainConfig
117
+ };
118
+ })), chainManager.multichain, batchSizeTarget);
119
+ }
120
+
121
+ function isProgressAtHead(chainManager) {
122
+ return ChainMap.values(chainManager.chainFetchers).every(function (cf) {
123
+ return cf.isProgressAtHead;
124
+ });
125
+ }
126
+
127
+ function isActivelyIndexing(chainManager) {
128
+ return ChainMap.values(chainManager.chainFetchers).every(ChainFetcher.isActivelyIndexing);
129
+ }
130
+
131
+ function getSafeCheckpointId(chainManager) {
132
+ var chainFetchers = ChainMap.values(chainManager.chainFetchers);
133
+ var result;
134
+ for(var idx = 0 ,idx_finish = chainFetchers.length; idx < idx_finish; ++idx){
135
+ var chainFetcher = chainFetchers[idx];
136
+ var safeCheckpointTracking = chainFetcher.safeCheckpointTracking;
137
+ if (safeCheckpointTracking !== undefined) {
138
+ var safeCheckpointId = SafeCheckpointTracking.getSafeCheckpointId(safeCheckpointTracking, chainFetcher.fetchState.knownHeight);
139
+ var current = result;
140
+ if (!(current !== undefined && safeCheckpointId >= current)) {
141
+ result = safeCheckpointId;
142
+ }
143
+
144
+ }
145
+
146
+ }
147
+ var id = result;
148
+ if (id !== undefined && id > 0n) {
149
+ return id;
150
+ }
151
+
152
+ }
153
+
154
+ export {
155
+ isProgressInReorgThreshold ,
156
+ calculateTargetBufferSize ,
157
+ makeFromDbState ,
158
+ getChainFetcher ,
159
+ setChainFetcher ,
160
+ nextItemIsNone ,
161
+ createBatch ,
162
+ isProgressAtHead ,
163
+ isActivelyIndexing ,
164
+ getSafeCheckpointId ,
165
+ }
166
+ /* Env Not a pure module */