envio 3.3.0-alpha.7 → 3.3.0-alpha.9

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 (95) hide show
  1. package/index.d.ts +23 -5
  2. package/package.json +6 -6
  3. package/src/Api.res +1 -1
  4. package/src/Api.res.mjs +1 -1
  5. package/src/ChainFetching.res +21 -10
  6. package/src/ChainFetching.res.mjs +11 -10
  7. package/src/ChainState.res +401 -171
  8. package/src/ChainState.res.mjs +270 -104
  9. package/src/ChainState.resi +19 -7
  10. package/src/Config.res +11 -27
  11. package/src/Config.res.mjs +8 -7
  12. package/src/Core.res +7 -0
  13. package/src/CrossChainState.res +82 -82
  14. package/src/CrossChainState.res.mjs +52 -59
  15. package/src/CrossChainState.resi +1 -1
  16. package/src/Ecosystem.res +3 -3
  17. package/src/Ecosystem.res.mjs +3 -3
  18. package/src/Envio.res +14 -9
  19. package/src/EnvioGlobal.res +53 -0
  20. package/src/EnvioGlobal.res.mjs +31 -0
  21. package/src/EventConfigBuilder.res +117 -69
  22. package/src/EventConfigBuilder.res.mjs +71 -34
  23. package/src/EventProcessing.res +19 -15
  24. package/src/EventProcessing.res.mjs +13 -12
  25. package/src/FetchState.res +410 -185
  26. package/src/FetchState.res.mjs +268 -253
  27. package/src/HandlerLoader.res +8 -113
  28. package/src/HandlerLoader.res.mjs +2 -88
  29. package/src/HandlerRegister.res +518 -144
  30. package/src/HandlerRegister.res.mjs +285 -133
  31. package/src/HandlerRegister.resi +24 -8
  32. package/src/IndexerState.res +6 -3
  33. package/src/IndexerState.res.mjs +3 -3
  34. package/src/IndexerState.resi +1 -1
  35. package/src/IndexingAddresses.res +10 -7
  36. package/src/IndexingAddresses.res.mjs +8 -7
  37. package/src/IndexingAddresses.resi +3 -1
  38. package/src/Internal.res +104 -39
  39. package/src/Internal.res.mjs +11 -1
  40. package/src/LogSelection.res +102 -165
  41. package/src/LogSelection.res.mjs +101 -116
  42. package/src/Main.res +49 -164
  43. package/src/Main.res.mjs +39 -104
  44. package/src/Metrics.res +43 -2
  45. package/src/Metrics.res.mjs +39 -3
  46. package/src/Prometheus.res +0 -35
  47. package/src/Prometheus.res.mjs +33 -68
  48. package/src/RawEvent.res +7 -2
  49. package/src/RawEvent.res.mjs +4 -4
  50. package/src/RollbackCommit.res +4 -1
  51. package/src/RollbackCommit.res.mjs +3 -2
  52. package/src/SimulateItems.res +20 -7
  53. package/src/SimulateItems.res.mjs +7 -11
  54. package/src/TestIndexer.res +1 -1
  55. package/src/TestIndexer.res.mjs +1 -1
  56. package/src/sources/BlockStore.res +46 -0
  57. package/src/sources/BlockStore.res.mjs +24 -0
  58. package/src/sources/EventRouter.res +19 -12
  59. package/src/sources/EventRouter.res.mjs +7 -5
  60. package/src/sources/Evm.res +58 -5
  61. package/src/sources/Evm.res.mjs +44 -5
  62. package/src/sources/EvmChain.res +14 -18
  63. package/src/sources/EvmChain.res.mjs +12 -13
  64. package/src/sources/FieldMask.res +39 -0
  65. package/src/sources/FieldMask.res.mjs +42 -0
  66. package/src/sources/Fuel.res +8 -3
  67. package/src/sources/Fuel.res.mjs +5 -4
  68. package/src/sources/HyperFuelSource.res +31 -40
  69. package/src/sources/HyperFuelSource.res.mjs +52 -44
  70. package/src/sources/HyperSync.res +31 -9
  71. package/src/sources/HyperSync.res.mjs +47 -31
  72. package/src/sources/HyperSync.resi +10 -3
  73. package/src/sources/HyperSyncClient.res +15 -4
  74. package/src/sources/HyperSyncHeightStream.res +1 -8
  75. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  76. package/src/sources/HyperSyncSource.res +58 -90
  77. package/src/sources/HyperSyncSource.res.mjs +57 -66
  78. package/src/sources/RpcSource.res +118 -120
  79. package/src/sources/RpcSource.res.mjs +92 -74
  80. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  81. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  82. package/src/sources/SimulateSource.res +5 -3
  83. package/src/sources/SimulateSource.res.mjs +12 -4
  84. package/src/sources/Source.res +19 -5
  85. package/src/sources/SourceManager.res +60 -10
  86. package/src/sources/SourceManager.res.mjs +54 -8
  87. package/src/sources/SourceManager.resi +10 -0
  88. package/src/sources/Svm.res +14 -10
  89. package/src/sources/Svm.res.mjs +23 -6
  90. package/src/sources/SvmHyperSyncClient.res +5 -6
  91. package/src/sources/SvmHyperSyncSource.res +82 -41
  92. package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
  93. package/src/sources/TransactionStore.res +6 -107
  94. package/src/sources/TransactionStore.res.mjs +5 -86
  95. package/svm.schema.json +19 -0
@@ -7,9 +7,10 @@ import * as Utils from "./Utils.res.mjs";
7
7
  import * as Logging from "./Logging.res.mjs";
8
8
  import * as ChainMap from "./ChainMap.res.mjs";
9
9
  import * as EvmChain from "./sources/EvmChain.res.mjs";
10
+ import * as FieldMask from "./sources/FieldMask.res.mjs";
11
+ import * as BlockStore from "./sources/BlockStore.res.mjs";
10
12
  import * as FetchState from "./FetchState.res.mjs";
11
13
  import * as Prometheus from "./Prometheus.res.mjs";
12
- import * as EventRouter from "./sources/EventRouter.res.mjs";
13
14
  import * as Stdlib_Null from "@rescript/runtime/lib/es6/Stdlib_Null.js";
14
15
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
15
16
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
@@ -39,12 +40,14 @@ function configAddresses(chainConfig) {
39
40
  return addresses;
40
41
  }
41
42
 
42
- function make(chainConfig, fetchState, indexingAddresses, sourceManager, reorgDetection, committedProgressBlockNumber, safeCheckpointTrackingOpt, numEventsProcessedOpt, timestampCaughtUpToHeadOrEndblockOpt, isProgressAtHeadOpt, transactionStoreOpt, logger) {
43
+ function make(chainConfig, fetchState, indexingAddresses, sourceManager, reorgDetection, committedProgressBlockNumber, safeCheckpointTrackingOpt, numEventsProcessedOpt, timestampCaughtUpToHeadOrEndblockOpt, isProgressAtHeadOpt, transactionStoreOpt, chainDensityOpt, blockStoreOpt, logger) {
43
44
  let safeCheckpointTracking = safeCheckpointTrackingOpt !== undefined ? Primitive_option.valFromOption(safeCheckpointTrackingOpt) : undefined;
44
45
  let numEventsProcessed = numEventsProcessedOpt !== undefined ? numEventsProcessedOpt : 0;
45
46
  let timestampCaughtUpToHeadOrEndblock = timestampCaughtUpToHeadOrEndblockOpt !== undefined ? Primitive_option.valFromOption(timestampCaughtUpToHeadOrEndblockOpt) : undefined;
46
47
  let isProgressAtHead = isProgressAtHeadOpt !== undefined ? isProgressAtHeadOpt : false;
47
48
  let transactionStore = transactionStoreOpt !== undefined ? Primitive_option.valFromOption(transactionStoreOpt) : TransactionStore.make("evm", false);
49
+ let chainDensity = chainDensityOpt !== undefined ? Primitive_option.valFromOption(chainDensityOpt) : undefined;
50
+ let blockStore = blockStoreOpt !== undefined ? Primitive_option.valFromOption(blockStoreOpt) : BlockStore.make("evm", false);
48
51
  return {
49
52
  logger: logger,
50
53
  fetchState: fetchState,
@@ -56,74 +59,31 @@ function make(chainConfig, fetchState, indexingAddresses, sourceManager, reorgDe
56
59
  committedProgressBlockNumber: committedProgressBlockNumber,
57
60
  numEventsProcessed: numEventsProcessed,
58
61
  pendingBudget: 0,
62
+ chainDensity: chainDensity,
59
63
  reorgDetection: reorgDetection,
60
64
  safeCheckpointTracking: safeCheckpointTracking,
61
- transactionStore: transactionStore
65
+ transactionStore: transactionStore,
66
+ blockStore: blockStore
62
67
  };
63
68
  }
64
69
 
65
- function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBlockOpt, progressBlockNumber, config, registrations, logger, timestampCaughtUpToHeadOrEndblock, numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, maxReorgDepth, knownHeightOpt, reducedPollingInterval) {
70
+ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firstEventBlockOpt, progressBlockNumber, config, registrationsByChainId, logger, timestampCaughtUpToHeadOrEndblock, numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, maxReorgDepth, knownHeightOpt, reducedPollingInterval) {
66
71
  let firstEventBlock = firstEventBlockOpt !== undefined ? Primitive_option.valFromOption(firstEventBlockOpt) : undefined;
67
72
  let knownHeight = knownHeightOpt !== undefined ? knownHeightOpt : 0;
68
- let eventRouter = EventRouter.empty();
69
- let eventConfigs = [];
70
- let notRegisteredEvents = [];
73
+ let match = Stdlib_Option.getOr(registrationsByChainId[chainConfig.id.toString()], {
74
+ onEventRegistrations: [],
75
+ onBlockRegistrations: []
76
+ });
77
+ let onEventRegistrations = match.onEventRegistrations;
71
78
  chainConfig.contracts.forEach(contract => {
72
- let contractName = contract.name;
73
- contract.events.forEach(eventConfig => {
74
- let hasContractRegister = Stdlib_Option.isSome(eventConfig.contractRegister);
75
- EventRouter.addOrThrow(eventRouter, eventConfig.id, undefined, contractName, eventConfig.isWildcard, eventConfig.name, ChainMap.Chain.makeUnsafe(chainConfig.id));
76
- let shouldBeIncluded;
77
- if (config.enableRawEvents) {
78
- shouldBeIncluded = true;
79
- } else {
80
- let isRegistered = hasContractRegister || Stdlib_Option.isSome(eventConfig.handler);
81
- if (!isRegistered) {
82
- notRegisteredEvents.push(eventConfig);
83
- }
84
- shouldBeIncluded = isRegistered;
85
- }
86
- let shouldSkip;
87
- try {
88
- let getEventFiltersOrThrow = eventConfig.getEventFiltersOrThrow;
89
- if (getEventFiltersOrThrow) {
90
- let match = getEventFiltersOrThrow(ChainMap.Chain.makeUnsafe(chainConfig.id));
91
- shouldSkip = match.TAG === "Static" ? match._0.length === 0 : false;
92
- } else {
93
- shouldSkip = false;
94
- }
95
- } catch (exn) {
96
- shouldSkip = false;
97
- }
98
- if (shouldBeIncluded && !shouldSkip) {
99
- eventConfigs.push(eventConfig);
100
- return;
101
- }
102
- });
103
79
  let startBlock = contract.startBlock;
104
80
  if (startBlock !== undefined && startBlock < chainConfig.startBlock) {
105
- return Stdlib_JsError.throwWithMessage(`The start block for contract "` + contractName + `" is less than the chain start block. This is not supported yet.`);
81
+ return Stdlib_JsError.throwWithMessage(`The start block for contract "` + contract.name + `" is less than the chain start block. This is not supported yet.`);
106
82
  }
107
83
  });
108
- if (Utils.$$Array.notEmpty(notRegisteredEvents)) {
109
- Logging.childInfo(logger, `The event` + (
110
- notRegisteredEvents.length > 1 ? "s" : ""
111
- ) + ` ` + notRegisteredEvents.map(eventConfig => eventConfig.contractName + `.` + eventConfig.name).join(", ") + ` don't have an event handler and skipped for indexing.`);
112
- }
113
- let onBlockConfigs = registrations.onBlockByChainId[chainConfig.id.toString()];
114
- if (onBlockConfigs !== undefined) {
115
- onBlockConfigs.forEach(onBlockConfig => {
116
- if (Stdlib_Option.getOr(onBlockConfig.startBlock, startBlock) < startBlock) {
117
- 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.`);
118
- }
119
- if (endBlock !== undefined && Stdlib_Option.getOr(onBlockConfig.endBlock, endBlock) > endBlock) {
120
- 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.`);
121
- }
122
- });
123
- }
124
- let contractConfigs = IndexingAddresses.makeContractConfigs(eventConfigs);
84
+ let contractConfigs = IndexingAddresses.makeContractConfigs(onEventRegistrations);
125
85
  let indexingAddressIndex = IndexingAddresses.make(contractConfigs, indexingAddresses);
126
- let fetchState = FetchState.make(startBlock, endBlock, eventConfigs, contractConfigs, indexingAddresses, config.maxAddrInPartition, chainConfig.id, (config.batchSize << 1), knownHeight, progressBlockNumber, onBlockConfigs, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock));
86
+ let fetchState = FetchState.make(startBlock, endBlock, onEventRegistrations, contractConfigs, indexingAddresses, config.maxAddrInPartition, chainConfig.id, (config.batchSize << 1), knownHeight, progressBlockNumber, match.onBlockRegistrations, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock));
127
87
  let chainReorgCheckpoints = Stdlib_Array.filterMap(reorgCheckpoints, reorgCheckpoint => {
128
88
  if (reorgCheckpoint.chain_id === chainConfig.id) {
129
89
  return reorgCheckpoint;
@@ -135,11 +95,6 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
135
95
  let sources$1;
136
96
  switch (sources.TAG) {
137
97
  case "EvmSourceConfig" :
138
- let evmContracts = chainConfig.contracts.map(contract => ({
139
- name: contract.name,
140
- abi: contract.abi,
141
- events: contract.events
142
- }));
143
98
  let evmRpcs = sources.rpcs.map(rpc => {
144
99
  let syncConfig = rpc.syncConfig;
145
100
  let ws = rpc.ws;
@@ -152,7 +107,7 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
152
107
  headers: headers
153
108
  };
154
109
  });
155
- sources$1 = EvmChain.makeSources(chain, evmContracts, sources.hypersync, evmRpcs, lowercaseAddresses);
110
+ sources$1 = EvmChain.makeSources(chain, onEventRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses);
156
111
  break;
157
112
  case "FuelSourceConfig" :
158
113
  sources$1 = [HyperFuelSource.make({
@@ -164,41 +119,40 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
164
119
  case "SvmSourceConfig" :
165
120
  let rpc = sources.rpc;
166
121
  let hypersync = sources.hypersync;
167
- if (hypersync !== undefined) {
168
- let svmEventConfigs = chainConfig.contracts.flatMap(contract => contract.events);
169
- sources$1 = [SvmHyperSyncSource.make({
122
+ sources$1 = hypersync !== undefined ? [SvmHyperSyncSource.make({
170
123
  chain: chain,
171
124
  endpointUrl: hypersync,
172
125
  apiToken: Env.envioApiToken,
173
- eventConfigs: svmEventConfigs,
126
+ onEventRegistrations: onEventRegistrations,
174
127
  clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis
175
- })];
176
- } else {
177
- sources$1 = rpc !== undefined ? [Svm.makeRPCSource(chain, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + chain.toString() + ` has no SVM data source`);
178
- }
128
+ })] : (
129
+ rpc !== undefined ? [Svm.makeRPCSource(chain, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + chain.toString() + ` has no SVM data source`)
130
+ );
179
131
  break;
180
132
  case "CustomSources" :
181
133
  sources$1 = sources._0;
182
134
  break;
183
135
  }
184
- return make(chainConfig, fetchState, indexingAddressIndex, SourceManager.make(sources$1, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), ReorgDetection.make(chainReorgCheckpoints, maxReorgDepth, config.shouldRollbackOnReorg), progressBlockNumber, Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, Primitive_option.some(TransactionStore.make(config.ecosystem.name, !lowercaseAddresses)), logger);
136
+ let firstEventBlock$1 = fetchState.firstEventBlock;
137
+ let chainDensity = firstEventBlock$1 !== undefined && progressBlockNumber > firstEventBlock$1 && numEventsProcessed > 0 ? numEventsProcessed / (progressBlockNumber - firstEventBlock$1 | 0) : undefined;
138
+ return make(chainConfig, fetchState, indexingAddressIndex, SourceManager.make(sources$1, isRealtime, undefined, undefined, undefined, reducedPollingInterval, undefined, undefined), ReorgDetection.make(chainReorgCheckpoints, maxReorgDepth, config.shouldRollbackOnReorg), progressBlockNumber, Primitive_option.some(SafeCheckpointTracking.make(maxReorgDepth, config.shouldRollbackOnReorg, chainReorgCheckpoints)), numEventsProcessed, Primitive_option.some(timestampCaughtUpToHeadOrEndblock), undefined, Primitive_option.some(TransactionStore.make(config.ecosystem.name, !lowercaseAddresses)), Primitive_option.some(chainDensity), Primitive_option.some(BlockStore.make(config.ecosystem.name, !lowercaseAddresses)), logger);
185
139
  }
186
140
 
187
- function makeFromConfig(chainConfig, config, registrations, knownHeight) {
141
+ function makeFromConfig(chainConfig, config, registrationsByChainId, knownHeight) {
188
142
  let logger = Logging.createChild({
189
143
  chainId: chainConfig.id
190
144
  });
191
- return makeInternal(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrations, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined);
145
+ return makeInternal(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrationsByChainId, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined);
192
146
  }
193
147
 
194
- function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrations, reducedPollingInterval) {
148
+ function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval) {
195
149
  let chainId = chainConfig.id;
196
150
  let logger = Logging.createChild({
197
151
  chainId: chainId
198
152
  });
199
153
  Prometheus.ProgressEventsCount.set(resumedChainState.numEventsProcessed, chainId);
200
154
  let progressBlockNumber = resumedChainState.progressBlockNumber >= 0 ? resumedChainState.progressBlockNumber : resumedChainState.startBlock - 1 | 0;
201
- return makeInternal(chainConfig, resumedChainState.indexingAddresses, resumedChainState.startBlock, resumedChainState.endBlock, Primitive_option.some(resumedChainState.firstEventBlockNumber), progressBlockNumber, config, registrations, logger, Env.updateSyncTimeOnRestart ? undefined : resumedChainState.timestampCaughtUpToHeadOrEndblock, resumedChainState.numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, resumedChainState.maxReorgDepth, resumedChainState.sourceBlockNumber, reducedPollingInterval);
155
+ return makeInternal(chainConfig, resumedChainState.indexingAddresses, resumedChainState.startBlock, resumedChainState.endBlock, Primitive_option.some(resumedChainState.firstEventBlockNumber), progressBlockNumber, config, registrationsByChainId, logger, Env.updateSyncTimeOnRestart ? undefined : resumedChainState.timestampCaughtUpToHeadOrEndblock, resumedChainState.numEventsProcessed, isInReorgThreshold, isRealtime, reorgCheckpoints, resumedChainState.maxReorgDepth, resumedChainState.sourceBlockNumber, reducedPollingInterval);
202
156
  }
203
157
 
204
158
  function logger(cs) {
@@ -261,8 +215,8 @@ function getProgressPercentage(cs) {
261
215
  return FetchState.getProgressPercentage(cs.fetchState);
262
216
  }
263
217
 
264
- function getProgressPercentageAt(cs, blockNumber) {
265
- return FetchState.getProgressPercentageAt(cs.fetchState, blockNumber);
218
+ function chainDensity(cs) {
219
+ return cs.chainDensity;
266
220
  }
267
221
 
268
222
  function hasReadyItem(cs) {
@@ -279,11 +233,80 @@ function isReadyToEnterReorgThreshold(cs) {
279
233
 
280
234
  function startFetchingQueries(cs, queries) {
281
235
  FetchState.startFetchingQueries(cs.fetchState, queries);
282
- cs.pendingBudget = cs.pendingBudget + Stdlib_Array.reduce(queries, 0, (acc, query) => acc + query.estResponseSize);
236
+ cs.pendingBudget = cs.pendingBudget + Stdlib_Array.reduce(queries, 0, (acc, query) => acc + query.itemsTarget);
237
+ }
238
+
239
+ function isReady(cs) {
240
+ return cs.timestampCaughtUpToHeadOrEndblock !== undefined;
241
+ }
242
+
243
+ function fetchCeiling(cs) {
244
+ let fetchState = cs.fetchState;
245
+ let endBlock = fetchState.endBlock;
246
+ if (endBlock !== undefined) {
247
+ return Primitive_int.min(endBlock, fetchState.knownHeight);
248
+ } else {
249
+ return fetchState.knownHeight;
250
+ }
251
+ }
252
+
253
+ function targetBlock(cs, chainTargetItems) {
254
+ let fetchState = cs.fetchState;
255
+ let fetchCeiling$1 = fetchCeiling(cs);
256
+ let bufferBlockNumber = FetchState.bufferBlockNumber(fetchState);
257
+ let density = cs.chainDensity;
258
+ if (density !== undefined && density > 0) {
259
+ return Primitive_int.min(fetchCeiling$1, bufferBlockNumber + (Math.ceil(chainTargetItems / density) | 0) | 0);
260
+ } else {
261
+ return fetchCeiling$1;
262
+ }
263
+ }
264
+
265
+ function progressRange(cs) {
266
+ let fetchState = cs.fetchState;
267
+ let lower = Stdlib_Option.getOr(fetchState.firstEventBlock, fetchState.startBlock);
268
+ let endBlock = fetchState.endBlock;
269
+ let upper = endBlock !== undefined ? endBlock : fetchState.knownHeight;
270
+ return [
271
+ lower,
272
+ upper
273
+ ];
274
+ }
275
+
276
+ function progressAtBlock(cs, blockNumber) {
277
+ let match = progressRange(cs);
278
+ let upper = match[1];
279
+ let lower = match[0];
280
+ if (upper <= lower) {
281
+ return 1;
282
+ } else {
283
+ return Primitive_float.max(0, Primitive_float.min(1, (blockNumber - lower | 0) / (upper - lower | 0)));
284
+ }
283
285
  }
284
286
 
285
- function getNextQuery(cs) {
286
- return FetchState.getNextQuery(cs.fetchState);
287
+ function blockAtProgress(cs, progress) {
288
+ let match = progressRange(cs);
289
+ let lower = match[0];
290
+ return lower + (Math.ceil(progress * (match[1] - lower | 0)) | 0) | 0;
291
+ }
292
+
293
+ function getNextQuery(cs, chainTargetItems, maxTargetBlock) {
294
+ let chainTargetBlock = targetBlock(cs, chainTargetItems);
295
+ let chainTargetBlock$1 = maxTargetBlock !== undefined ? Primitive_int.min(chainTargetBlock, maxTargetBlock) : chainTargetBlock;
296
+ let density = cs.chainDensity;
297
+ let chainTargetItems$1;
298
+ if (density !== undefined) {
299
+ if (density > 0) {
300
+ let rangeCost = density * (chainTargetBlock$1 - FetchState.bufferBlockNumber(cs.fetchState) | 0);
301
+ let rangeCost$1 = chainTargetBlock$1 >= fetchCeiling(cs) && cs.timestampCaughtUpToHeadOrEndblock !== undefined ? rangeCost * 3 : rangeCost;
302
+ chainTargetItems$1 = Primitive_float.min(chainTargetItems, Math.ceil(rangeCost$1) + cs.pendingBudget);
303
+ } else {
304
+ chainTargetItems$1 = Primitive_float.min(chainTargetItems, 5000 + cs.pendingBudget);
305
+ }
306
+ } else {
307
+ chainTargetItems$1 = Primitive_float.min(chainTargetItems, 5000 + cs.pendingBudget);
308
+ }
309
+ return FetchState.getNextQuery(cs.fetchState, chainTargetBlock$1, chainTargetItems$1);
287
310
  }
288
311
 
289
312
  function dispatch(cs, executeQuery, waitForNewBlock, onNewBlock, action, stateId) {
@@ -314,10 +337,6 @@ function isActivelyIndexing(cs) {
314
337
  return FetchState.isActivelyIndexing(cs.fetchState);
315
338
  }
316
339
 
317
- function isReady(cs) {
318
- return cs.timestampCaughtUpToHeadOrEndblock !== undefined;
319
- }
320
-
321
340
  function isFetchingAtHead(cs) {
322
341
  return FetchState.isFetchingAtHead(cs.fetchState);
323
342
  }
@@ -330,25 +349,144 @@ function isAtHeadWithoutEndBlock(cs) {
330
349
  }
331
350
  }
332
351
 
333
- function materializeBatchItems(cs, items) {
334
- return TransactionStore.materializeItems(cs.transactionStore, items);
352
+ function groupBatchItems(items, includeBlocks) {
353
+ let txBlockNumbers = [];
354
+ let transactionIndices = [];
355
+ let transactionMasks = [];
356
+ let payloadGroups = [];
357
+ let anyTransactionFieldSelected = {
358
+ contents: false
359
+ };
360
+ let blockBlockNumbers = [];
361
+ let blockMasks = [];
362
+ let blockItemGroups = [];
363
+ items.forEach(item => {
364
+ if (item.kind !== 0) {
365
+ return;
366
+ }
367
+ let blockNumber = item.blockNumber;
368
+ let match = item.payload.transaction;
369
+ if (match == null) {
370
+ let transactionIndex = item.transactionIndex;
371
+ let mask = item.onEventRegistration.eventConfig.transactionFieldMask;
372
+ if (mask !== 0) {
373
+ anyTransactionFieldSelected.contents = true;
374
+ }
375
+ let last = payloadGroups.length - 1 | 0;
376
+ if (last >= 0 && txBlockNumbers[last] === blockNumber && transactionIndices[last] === transactionIndex) {
377
+ payloadGroups[last].push(item.payload);
378
+ transactionMasks[last] = FieldMask.orMask(transactionMasks[last], mask);
379
+ } else {
380
+ txBlockNumbers.push(blockNumber);
381
+ transactionIndices.push(transactionIndex);
382
+ transactionMasks.push(mask);
383
+ payloadGroups.push([item.payload]);
384
+ }
385
+ }
386
+ if (!includeBlocks) {
387
+ return;
388
+ }
389
+ let match$1 = item.payload.block;
390
+ if (!(match$1 == null)) {
391
+ return;
392
+ }
393
+ let mask$1 = item.onEventRegistration.eventConfig.blockFieldMask;
394
+ let last$1 = blockItemGroups.length - 1 | 0;
395
+ if (last$1 >= 0 && blockBlockNumbers[last$1] === blockNumber) {
396
+ blockItemGroups[last$1].push(item);
397
+ blockMasks[last$1] = FieldMask.orMask(blockMasks[last$1], mask$1);
398
+ } else {
399
+ blockBlockNumbers.push(blockNumber);
400
+ blockMasks.push(mask$1);
401
+ blockItemGroups.push([item]);
402
+ }
403
+ });
404
+ return [
405
+ {
406
+ txBlockNumbers: txBlockNumbers,
407
+ transactionIndices: transactionIndices,
408
+ transactionMasks: transactionMasks,
409
+ payloadGroups: payloadGroups,
410
+ anyTransactionFieldSelected: anyTransactionFieldSelected.contents
411
+ },
412
+ {
413
+ blockBlockNumbers: blockBlockNumbers,
414
+ blockMasks: blockMasks,
415
+ blockItemGroups: blockItemGroups
416
+ }
417
+ ];
335
418
  }
336
419
 
337
- function materializePageItems(items, page) {
338
- if (page !== undefined) {
339
- return TransactionStore.materializeItems(Primitive_option.valFromOption(page), items);
340
- } else {
341
- return Promise.resolve();
420
+ async function applyTransactionGroups(store, g) {
421
+ if (!Utils.$$Array.notEmpty(g.payloadGroups)) {
422
+ return;
423
+ }
424
+ if (g.anyTransactionFieldSelected) {
425
+ let txs = await store.materialize(g.txBlockNumbers, g.transactionIndices, g.transactionMasks);
426
+ g.payloadGroups.forEach((payloads, i) => {
427
+ let tx = txs[i];
428
+ payloads.forEach(payload => {
429
+ payload.transaction = tx;
430
+ });
431
+ });
432
+ return;
342
433
  }
434
+ g.payloadGroups.forEach(payloads => {
435
+ payloads.forEach(payload => {
436
+ payload.transaction = {};
437
+ });
438
+ });
343
439
  }
344
440
 
345
- function handleQueryResult(cs, query, newItems, newItemsWithDcs, latestFetchedBlock, knownHeight, page) {
346
- if (page !== undefined) {
347
- cs.transactionStore.merge(Primitive_option.valFromOption(page));
441
+ async function applyBlockGroups(store, g) {
442
+ if (!Utils.$$Array.notEmpty(g.blockItemGroups)) {
443
+ return;
444
+ }
445
+ let blocks = await store.materialize(g.blockBlockNumbers, g.blockMasks);
446
+ g.blockItemGroups.forEach((group, i) => {
447
+ let block = blocks[i];
448
+ group.forEach(ei => {
449
+ ei.payload.block = block;
450
+ });
451
+ });
452
+ }
453
+
454
+ function includeBlocksForEcosystem(ecosystem) {
455
+ switch (ecosystem) {
456
+ case "fuel" :
457
+ return false;
458
+ case "evm" :
459
+ case "svm" :
460
+ return true;
461
+ }
462
+ }
463
+
464
+ async function materializeBatchItems(cs, items, ecosystem) {
465
+ let match = groupBatchItems(items, includeBlocksForEcosystem(ecosystem));
466
+ await Promise.all([
467
+ applyTransactionGroups(cs.transactionStore, match[0]),
468
+ applyBlockGroups(cs.blockStore, match[1])
469
+ ]);
470
+ }
471
+
472
+ async function materializePageItems(items, transactionStore, blockStore, ecosystem) {
473
+ let match = groupBatchItems(items, includeBlocksForEcosystem(ecosystem));
474
+ await Promise.all([
475
+ transactionStore !== undefined ? applyTransactionGroups(Primitive_option.valFromOption(transactionStore), match[0]) : Promise.resolve(),
476
+ blockStore !== undefined ? applyBlockGroups(Primitive_option.valFromOption(blockStore), match[1]) : Promise.resolve()
477
+ ]);
478
+ }
479
+
480
+ function handleQueryResult(cs, query, newItems, newItemsWithDcs, latestFetchedBlock, knownHeight, txPage, blockPage) {
481
+ if (txPage !== undefined) {
482
+ cs.transactionStore.merge(Primitive_option.valFromOption(txPage));
483
+ }
484
+ if (blockPage !== undefined) {
485
+ cs.blockStore.merge(Primitive_option.valFromOption(blockPage));
348
486
  }
349
487
  let fs = newItemsWithDcs.length !== 0 ? FetchState.registerDynamicContracts(cs.fetchState, cs.indexingAddresses, newItemsWithDcs) : cs.fetchState;
350
488
  cs.fetchState = FetchState.updateKnownHeight(FetchState.handleQueryResult(fs, cs.indexingAddresses, query, latestFetchedBlock, newItems), knownHeight);
351
- cs.pendingBudget = Primitive_float.max(0, cs.pendingBudget - query.estResponseSize);
489
+ cs.pendingBudget = Primitive_float.max(0, cs.pendingBudget - query.itemsTarget);
352
490
  }
353
491
 
354
492
  function registerReorgGuard(cs, blockHashes, knownHeight) {
@@ -387,7 +525,7 @@ function setEndBlockToFirstEvent(cs, blockNumber) {
387
525
  blockLag: init.blockLag,
388
526
  buffer: init.buffer,
389
527
  maxOnBlockBufferSize: init.maxOnBlockBufferSize,
390
- onBlockConfigs: init.onBlockConfigs,
528
+ onBlockRegistrations: init.onBlockRegistrations,
391
529
  knownHeight: init.knownHeight,
392
530
  firstEventBlock: init.firstEventBlock
393
531
  };
@@ -405,7 +543,7 @@ function setEndBlockToFirstEvent(cs, blockNumber) {
405
543
  blockLag: init$1.blockLag,
406
544
  buffer: init$1.buffer,
407
545
  maxOnBlockBufferSize: init$1.maxOnBlockBufferSize,
408
- onBlockConfigs: init$1.onBlockConfigs,
546
+ onBlockRegistrations: init$1.onBlockRegistrations,
409
547
  knownHeight: init$1.knownHeight,
410
548
  firstEventBlock: init$1.firstEventBlock
411
549
  };
@@ -465,7 +603,7 @@ function advanceAfterBatch(cs, batch, enteringReorgThreshold) {
465
603
  }
466
604
  }
467
605
 
468
- function applyBatchProgress(cs, batch) {
606
+ function applyBatchProgress(cs, batch, blockTimestampName) {
469
607
  let chainId = cs.chainConfig.id;
470
608
  let chainAfterBatch = batch.progressedChainsById[chainId];
471
609
  if (chainAfterBatch === undefined) {
@@ -477,9 +615,9 @@ function applyBatchProgress(cs, batch) {
477
615
  if (cs.numEventsProcessed !== chainAfterBatch.totalEventsProcessed) {
478
616
  Prometheus.ProgressEventsCount.set(chainAfterBatch.totalEventsProcessed, chainId);
479
617
  }
480
- let eventItem = Batch.findLastEventItem(batch, chainId);
481
- if (eventItem !== undefined) {
482
- let blockTimestampMs = eventItem.timestamp * 1000 | 0;
618
+ let blockTimestamp = Stdlib_Option.flatMap(Stdlib_Option.flatMap(Batch.findLastEventItem(batch, chainId), eventItem => Primitive_option.fromNullable(eventItem.payload.block)), block => block[blockTimestampName]);
619
+ if (blockTimestamp !== undefined) {
620
+ let blockTimestampMs = Primitive_option.valFromOption(blockTimestamp) * 1000 | 0;
483
621
  Prometheus.ProgressLatency.set((Date.now() | 0) - blockTimestampMs | 0, chainId);
484
622
  }
485
623
  let match = cs.fetchState.firstEventBlock;
@@ -498,15 +636,38 @@ function applyBatchProgress(cs, batch) {
498
636
  blockLag: init.blockLag,
499
637
  buffer: init.buffer,
500
638
  maxOnBlockBufferSize: init.maxOnBlockBufferSize,
501
- onBlockConfigs: init.onBlockConfigs,
639
+ onBlockRegistrations: init.onBlockRegistrations,
502
640
  knownHeight: init.knownHeight,
503
641
  firstEventBlock: firstEventBlock
504
642
  };
505
643
  }
506
644
  }
645
+ let deltaBlocks = chainAfterBatch.progressBlockNumber - cs.committedProgressBlockNumber | 0;
646
+ if (deltaBlocks > 0) {
647
+ let deltaEvents = chainAfterBatch.totalEventsProcessed - cs.numEventsProcessed;
648
+ let match$1 = cs.chainDensity;
649
+ let match$2 = deltaEvents > 0;
650
+ let exit = 0;
651
+ if (match$1 !== undefined || match$2) {
652
+ exit = 1;
653
+ }
654
+ if (exit === 1) {
655
+ let batchDensity = deltaEvents / deltaBlocks;
656
+ let oldDensity = cs.chainDensity;
657
+ let tmp;
658
+ if (oldDensity !== undefined) {
659
+ let alpha = Primitive_float.min(1, deltaBlocks / 100);
660
+ tmp = oldDensity * (1 - alpha) + batchDensity * alpha;
661
+ } else {
662
+ tmp = batchDensity;
663
+ }
664
+ cs.chainDensity = tmp;
665
+ }
666
+ }
507
667
  cs.committedProgressBlockNumber = chainAfterBatch.progressBlockNumber;
508
668
  cs.numEventsProcessed = chainAfterBatch.totalEventsProcessed;
509
669
  cs.transactionStore.prune(chainAfterBatch.progressBlockNumber);
670
+ cs.blockStore.prune(chainAfterBatch.progressBlockNumber);
510
671
  cs.isProgressAtHead = cs.isProgressAtHead || chainAfterBatch.isProgressAtHeadWhenBatchCreated;
511
672
  let safeCheckpointTracking = cs.safeCheckpointTracking;
512
673
  if (safeCheckpointTracking !== undefined) {
@@ -529,6 +690,7 @@ function rollback(cs, newProgressBlockNumber, eventsProcessedDiff, rollbackTarge
529
690
  cs.reorgDetection = ReorgDetection.rollbackToValidBlockNumber(cs.reorgDetection, rollbackTargetBlockNumber);
530
691
  cs.fetchState = FetchState.rollback(cs.fetchState, cs.indexingAddresses, rollbackTargetBlockNumber);
531
692
  cs.transactionStore.rollback(rollbackTargetBlockNumber);
693
+ cs.blockStore.rollback(rollbackTargetBlockNumber);
532
694
  cs.committedProgressBlockNumber = Primitive_int.min(cs.committedProgressBlockNumber, rollbackTargetBlockNumber);
533
695
  return;
534
696
  } else {
@@ -551,6 +713,7 @@ function rollback(cs, newProgressBlockNumber, eventsProcessedDiff, rollbackTarge
551
713
  }
552
714
  cs.fetchState = FetchState.rollback(cs.fetchState, cs.indexingAddresses, newProgressBlockNumber);
553
715
  cs.transactionStore.rollback(newProgressBlockNumber);
716
+ cs.blockStore.rollback(newProgressBlockNumber);
554
717
  cs.committedProgressBlockNumber = newProgressBlockNumber;
555
718
  cs.numEventsProcessed = newTotalEventsProcessed;
556
719
  }
@@ -576,9 +739,12 @@ export {
576
739
  bufferSize,
577
740
  bufferReadyCount,
578
741
  getProgressPercentage,
579
- getProgressPercentageAt,
742
+ chainDensity,
580
743
  hasReadyItem,
581
744
  isReadyToEnterReorgThreshold,
745
+ targetBlock,
746
+ progressAtBlock,
747
+ blockAtProgress,
582
748
  getNextQuery,
583
749
  dispatch,
584
750
  toChainData,
@@ -17,13 +17,15 @@ let make: (
17
17
  ~timestampCaughtUpToHeadOrEndblock: option<Date.t>=?,
18
18
  ~isProgressAtHead: bool=?,
19
19
  ~transactionStore: TransactionStore.t=?,
20
+ ~chainDensity: option<float>=?,
21
+ ~blockStore: BlockStore.t=?,
20
22
  ~logger: Pino.t,
21
23
  ) => t
22
24
 
23
25
  let makeFromConfig: (
24
26
  Config.chain,
25
27
  ~config: Config.t,
26
- ~registrations: HandlerRegister.registrations,
28
+ ~registrationsByChainId: HandlerRegister.registrationsByChainId,
27
29
  ~knownHeight: int,
28
30
  ) => t
29
31
 
@@ -34,7 +36,7 @@ let makeFromDbState: (
34
36
  ~isInReorgThreshold: bool,
35
37
  ~isRealtime: bool,
36
38
  ~config: Config.t,
37
- ~registrations: HandlerRegister.registrations,
39
+ ~registrationsByChainId: HandlerRegister.registrationsByChainId,
38
40
  ~reducedPollingInterval: int=?,
39
41
  ) => t
40
42
 
@@ -57,12 +59,15 @@ let contractAddresses: (t, ~contractName: string) => array<Address.t>
57
59
  let bufferSize: t => int
58
60
  let bufferReadyCount: t => int
59
61
  let getProgressPercentage: t => float
60
- let getProgressPercentageAt: (t, ~blockNumber: int) => float
62
+ let chainDensity: t => option<float>
61
63
  let hasReadyItem: t => bool
62
64
  let isReadyToEnterReorgThreshold: t => bool
63
65
 
64
66
  // Fetch control.
65
- let getNextQuery: t => FetchState.nextQuery
67
+ let targetBlock: (t, ~chainTargetItems: float) => int
68
+ let progressAtBlock: (t, ~blockNumber: int) => float
69
+ let blockAtProgress: (t, ~progress: float) => int
70
+ let getNextQuery: (t, ~chainTargetItems: float, ~maxTargetBlock: int=?) => FetchState.nextQuery
66
71
  let dispatch: (
67
72
  t,
68
73
  ~executeQuery: FetchState.query => promise<unit>,
@@ -110,11 +115,18 @@ let handleQueryResult: (
110
115
  ~latestFetchedBlock: FetchState.blockNumberAndTimestamp,
111
116
  ~knownHeight: int,
112
117
  ~transactionStore: option<TransactionStore.t>,
118
+ ~blockStore: option<BlockStore.t>,
113
119
  ) => unit
114
- let materializeBatchItems: (t, ~items: array<Internal.item>) => promise<unit>
120
+ let materializeBatchItems: (
121
+ t,
122
+ ~items: array<Internal.item>,
123
+ ~ecosystem: Ecosystem.name,
124
+ ) => promise<unit>
115
125
  let materializePageItems: (
116
126
  ~items: array<Internal.item>,
117
- ~page: option<TransactionStore.t>,
127
+ ~transactionStore: option<TransactionStore.t>,
128
+ ~blockStore: option<BlockStore.t>,
129
+ ~ecosystem: Ecosystem.name,
118
130
  ) => promise<unit>
119
131
  let registerReorgGuard: (
120
132
  t,
@@ -126,7 +138,7 @@ let updateKnownHeight: (t, ~knownHeight: int) => unit
126
138
  let setEndBlockToFirstEvent: (t, ~blockNumber: int) => unit
127
139
  let enterReorgThreshold: t => unit
128
140
  let advanceAfterBatch: (t, ~batch: Batch.t, ~enteringReorgThreshold: bool) => unit
129
- let applyBatchProgress: (t, ~batch: Batch.t) => unit
141
+ let applyBatchProgress: (t, ~batch: Batch.t, ~blockTimestampName: string) => unit
130
142
  let markReady: t => unit
131
143
  let rollback: (
132
144
  t,