envio 3.3.0-alpha.6 → 3.3.0-alpha.8

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 (93) hide show
  1. package/index.d.ts +23 -5
  2. package/package.json +6 -6
  3. package/src/Address.res +5 -2
  4. package/src/Address.res.mjs +3 -1
  5. package/src/Api.res +1 -1
  6. package/src/Api.res.mjs +1 -1
  7. package/src/ChainFetching.res +34 -34
  8. package/src/ChainFetching.res.mjs +29 -29
  9. package/src/ChainState.res +328 -165
  10. package/src/ChainState.res.mjs +205 -100
  11. package/src/ChainState.resi +16 -7
  12. package/src/Config.res +55 -27
  13. package/src/Config.res.mjs +46 -7
  14. package/src/ContractRegisterContext.res +2 -12
  15. package/src/ContractRegisterContext.res.mjs +3 -5
  16. package/src/Core.res +7 -0
  17. package/src/CrossChainState.res +54 -79
  18. package/src/CrossChainState.res.mjs +45 -60
  19. package/src/CrossChainState.resi +1 -1
  20. package/src/Ecosystem.res +3 -3
  21. package/src/Ecosystem.res.mjs +3 -3
  22. package/src/Envio.res +14 -9
  23. package/src/EventConfigBuilder.res +105 -56
  24. package/src/EventConfigBuilder.res.mjs +69 -33
  25. package/src/EventProcessing.res +19 -15
  26. package/src/EventProcessing.res.mjs +13 -12
  27. package/src/FetchState.res +383 -182
  28. package/src/FetchState.res.mjs +260 -264
  29. package/src/HandlerLoader.res +7 -112
  30. package/src/HandlerLoader.res.mjs +1 -87
  31. package/src/HandlerRegister.res +209 -6
  32. package/src/HandlerRegister.res.mjs +90 -5
  33. package/src/HandlerRegister.resi +13 -2
  34. package/src/IndexerState.res +6 -3
  35. package/src/IndexerState.res.mjs +3 -3
  36. package/src/IndexerState.resi +1 -1
  37. package/src/IndexingAddresses.res +10 -7
  38. package/src/IndexingAddresses.res.mjs +8 -7
  39. package/src/IndexingAddresses.resi +3 -1
  40. package/src/Internal.res +82 -36
  41. package/src/Internal.res.mjs +11 -1
  42. package/src/Main.res +22 -23
  43. package/src/Main.res.mjs +15 -17
  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/SimulateItems.res +26 -8
  51. package/src/SimulateItems.res.mjs +11 -14
  52. package/src/TestIndexer.res +1 -1
  53. package/src/TestIndexer.res.mjs +1 -1
  54. package/src/sources/BlockStore.res +46 -0
  55. package/src/sources/BlockStore.res.mjs +24 -0
  56. package/src/sources/EventRouter.res +19 -12
  57. package/src/sources/EventRouter.res.mjs +7 -5
  58. package/src/sources/Evm.res +54 -4
  59. package/src/sources/Evm.res.mjs +43 -4
  60. package/src/sources/EvmChain.res +14 -18
  61. package/src/sources/EvmChain.res.mjs +12 -13
  62. package/src/sources/FieldMask.res +39 -0
  63. package/src/sources/FieldMask.res.mjs +42 -0
  64. package/src/sources/Fuel.res +5 -2
  65. package/src/sources/Fuel.res.mjs +4 -3
  66. package/src/sources/HyperFuelSource.res +32 -40
  67. package/src/sources/HyperFuelSource.res.mjs +53 -45
  68. package/src/sources/HyperSync.res +35 -9
  69. package/src/sources/HyperSync.res.mjs +52 -35
  70. package/src/sources/HyperSync.resi +11 -3
  71. package/src/sources/HyperSyncClient.res +15 -4
  72. package/src/sources/HyperSyncHeightStream.res +1 -8
  73. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  74. package/src/sources/HyperSyncSource.res +39 -58
  75. package/src/sources/HyperSyncSource.res.mjs +44 -44
  76. package/src/sources/RpcSource.res +114 -92
  77. package/src/sources/RpcSource.res.mjs +77 -46
  78. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  79. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  80. package/src/sources/SimulateSource.res +6 -3
  81. package/src/sources/SimulateSource.res.mjs +13 -5
  82. package/src/sources/Source.res +25 -5
  83. package/src/sources/SourceManager.res +66 -3
  84. package/src/sources/SourceManager.res.mjs +55 -7
  85. package/src/sources/SourceManager.resi +10 -0
  86. package/src/sources/Svm.res +15 -10
  87. package/src/sources/Svm.res.mjs +24 -7
  88. package/src/sources/SvmHyperSyncClient.res +5 -6
  89. package/src/sources/SvmHyperSyncSource.res +84 -41
  90. package/src/sources/SvmHyperSyncSource.res.mjs +90 -43
  91. package/src/sources/TransactionStore.res +6 -107
  92. package/src/sources/TransactionStore.res.mjs +5 -86
  93. 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,40 @@ 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 onBlockRegistrations = match.onBlockRegistrations;
78
+ let onEventRegistrations = match.onEventRegistrations;
71
79
  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
80
  let startBlock = contract.startBlock;
104
81
  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.`);
82
+ return Stdlib_JsError.throwWithMessage(`The start block for contract "` + contract.name + `" is less than the chain start block. This is not supported yet.`);
106
83
  }
107
84
  });
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);
85
+ onBlockRegistrations.forEach(onBlockRegistration => {
86
+ if (Stdlib_Option.getOr(onBlockRegistration.startBlock, startBlock) < startBlock) {
87
+ Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + onBlockRegistration.name + `" is less than the chain start block (` + startBlock.toString() + `). This is not supported yet.`);
88
+ }
89
+ if (endBlock !== undefined && Stdlib_Option.getOr(onBlockRegistration.endBlock, endBlock) > endBlock) {
90
+ return Stdlib_JsError.throwWithMessage(`The end block for onBlock handler "` + onBlockRegistration.name + `" is greater than the chain end block (` + endBlock.toString() + `). This is not supported yet.`);
91
+ }
92
+ });
93
+ let contractConfigs = IndexingAddresses.makeContractConfigs(onEventRegistrations);
125
94
  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));
95
+ let fetchState = FetchState.make(startBlock, endBlock, onEventRegistrations, contractConfigs, indexingAddresses, config.maxAddrInPartition, chainConfig.id, (config.batchSize << 1), knownHeight, progressBlockNumber, onBlockRegistrations, Primitive_int.max(!config.shouldRollbackOnReorg || isInReorgThreshold ? 0 : chainConfig.maxReorgDepth, chainConfig.blockLag), Primitive_option.some(firstEventBlock));
127
96
  let chainReorgCheckpoints = Stdlib_Array.filterMap(reorgCheckpoints, reorgCheckpoint => {
128
97
  if (reorgCheckpoint.chain_id === chainConfig.id) {
129
98
  return reorgCheckpoint;
@@ -135,11 +104,6 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
135
104
  let sources$1;
136
105
  switch (sources.TAG) {
137
106
  case "EvmSourceConfig" :
138
- let evmContracts = chainConfig.contracts.map(contract => ({
139
- name: contract.name,
140
- abi: contract.abi,
141
- events: contract.events
142
- }));
143
107
  let evmRpcs = sources.rpcs.map(rpc => {
144
108
  let syncConfig = rpc.syncConfig;
145
109
  let ws = rpc.ws;
@@ -152,7 +116,7 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
152
116
  headers: headers
153
117
  };
154
118
  });
155
- sources$1 = EvmChain.makeSources(chain, evmContracts, sources.hypersync, evmRpcs, lowercaseAddresses);
119
+ sources$1 = EvmChain.makeSources(chain, onEventRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses);
156
120
  break;
157
121
  case "FuelSourceConfig" :
158
122
  sources$1 = [HyperFuelSource.make({
@@ -164,41 +128,40 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
164
128
  case "SvmSourceConfig" :
165
129
  let rpc = sources.rpc;
166
130
  let hypersync = sources.hypersync;
167
- if (hypersync !== undefined) {
168
- let svmEventConfigs = chainConfig.contracts.flatMap(contract => contract.events);
169
- sources$1 = [SvmHyperSyncSource.make({
131
+ sources$1 = hypersync !== undefined ? [SvmHyperSyncSource.make({
170
132
  chain: chain,
171
133
  endpointUrl: hypersync,
172
134
  apiToken: Env.envioApiToken,
173
- eventConfigs: svmEventConfigs,
135
+ onEventRegistrations: onEventRegistrations,
174
136
  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
- }
137
+ })] : (
138
+ rpc !== undefined ? [Svm.makeRPCSource(chain, rpc, undefined)] : Stdlib_JsError.throwWithMessage(`Chain ` + chain.toString() + ` has no SVM data source`)
139
+ );
179
140
  break;
180
141
  case "CustomSources" :
181
142
  sources$1 = sources._0;
182
143
  break;
183
144
  }
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);
145
+ let firstEventBlock$1 = fetchState.firstEventBlock;
146
+ let chainDensity = firstEventBlock$1 !== undefined && progressBlockNumber > firstEventBlock$1 && numEventsProcessed > 0 ? numEventsProcessed / (progressBlockNumber - firstEventBlock$1 | 0) : undefined;
147
+ 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
148
  }
186
149
 
187
- function makeFromConfig(chainConfig, config, registrations, knownHeight) {
150
+ function makeFromConfig(chainConfig, config, registrationsByChainId, knownHeight) {
188
151
  let logger = Logging.createChild({
189
152
  chainId: chainConfig.id
190
153
  });
191
- return makeInternal(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrations, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined);
154
+ return makeInternal(chainConfig, configAddresses(chainConfig), chainConfig.startBlock, chainConfig.endBlock, undefined, -1, config, registrationsByChainId, logger, undefined, 0, false, false, [], chainConfig.maxReorgDepth, knownHeight, undefined);
192
155
  }
193
156
 
194
- function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrations, reducedPollingInterval) {
157
+ function makeFromDbState(chainConfig, resumedChainState, reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval) {
195
158
  let chainId = chainConfig.id;
196
159
  let logger = Logging.createChild({
197
160
  chainId: chainId
198
161
  });
199
162
  Prometheus.ProgressEventsCount.set(resumedChainState.numEventsProcessed, chainId);
200
163
  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);
164
+ 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
165
  }
203
166
 
204
167
  function logger(cs) {
@@ -261,8 +224,8 @@ function getProgressPercentage(cs) {
261
224
  return FetchState.getProgressPercentage(cs.fetchState);
262
225
  }
263
226
 
264
- function getProgressPercentageAt(cs, blockNumber) {
265
- return FetchState.getProgressPercentageAt(cs.fetchState, blockNumber);
227
+ function chainDensity(cs) {
228
+ return cs.chainDensity;
266
229
  }
267
230
 
268
231
  function hasReadyItem(cs) {
@@ -279,11 +242,16 @@ function isReadyToEnterReorgThreshold(cs) {
279
242
 
280
243
  function startFetchingQueries(cs, queries) {
281
244
  FetchState.startFetchingQueries(cs.fetchState, queries);
282
- cs.pendingBudget = cs.pendingBudget + Stdlib_Array.reduce(queries, 0, (acc, query) => acc + query.estResponseSize);
245
+ cs.pendingBudget = cs.pendingBudget + Stdlib_Array.reduce(queries, 0, (acc, query) => acc + query.itemsTarget);
283
246
  }
284
247
 
285
- function getNextQuery(cs, budget) {
286
- return FetchState.getNextQuery(cs.fetchState, budget, cs.pendingBudget);
248
+ function getNextQuery(cs, chainTargetItems) {
249
+ let fetchState = cs.fetchState;
250
+ let knownHeight = fetchState.knownHeight;
251
+ let bufferBlockNumber = FetchState.bufferBlockNumber(fetchState);
252
+ let density = cs.chainDensity;
253
+ let chainTargetBlock = density !== undefined && density > 0 ? Primitive_int.min(knownHeight, bufferBlockNumber + (Math.ceil(chainTargetItems / density) | 0) | 0) : knownHeight;
254
+ return FetchState.getNextQuery(fetchState, chainTargetBlock, chainTargetItems);
287
255
  }
288
256
 
289
257
  function dispatch(cs, executeQuery, waitForNewBlock, onNewBlock, action, stateId) {
@@ -330,25 +298,144 @@ function isAtHeadWithoutEndBlock(cs) {
330
298
  }
331
299
  }
332
300
 
333
- function materializeBatchItems(cs, items) {
334
- return TransactionStore.materializeItems(cs.transactionStore, items);
301
+ function groupBatchItems(items, includeBlocks) {
302
+ let txBlockNumbers = [];
303
+ let transactionIndices = [];
304
+ let transactionMasks = [];
305
+ let payloadGroups = [];
306
+ let anyTransactionFieldSelected = {
307
+ contents: false
308
+ };
309
+ let blockBlockNumbers = [];
310
+ let blockMasks = [];
311
+ let blockItemGroups = [];
312
+ items.forEach(item => {
313
+ if (item.kind !== 0) {
314
+ return;
315
+ }
316
+ let blockNumber = item.blockNumber;
317
+ let match = item.payload.transaction;
318
+ if (match == null) {
319
+ let transactionIndex = item.transactionIndex;
320
+ let mask = item.onEventRegistration.eventConfig.transactionFieldMask;
321
+ if (mask !== 0) {
322
+ anyTransactionFieldSelected.contents = true;
323
+ }
324
+ let last = payloadGroups.length - 1 | 0;
325
+ if (last >= 0 && txBlockNumbers[last] === blockNumber && transactionIndices[last] === transactionIndex) {
326
+ payloadGroups[last].push(item.payload);
327
+ transactionMasks[last] = FieldMask.orMask(transactionMasks[last], mask);
328
+ } else {
329
+ txBlockNumbers.push(blockNumber);
330
+ transactionIndices.push(transactionIndex);
331
+ transactionMasks.push(mask);
332
+ payloadGroups.push([item.payload]);
333
+ }
334
+ }
335
+ if (!includeBlocks) {
336
+ return;
337
+ }
338
+ let match$1 = item.payload.block;
339
+ if (!(match$1 == null)) {
340
+ return;
341
+ }
342
+ let mask$1 = item.onEventRegistration.eventConfig.blockFieldMask;
343
+ let last$1 = blockItemGroups.length - 1 | 0;
344
+ if (last$1 >= 0 && blockBlockNumbers[last$1] === blockNumber) {
345
+ blockItemGroups[last$1].push(item);
346
+ blockMasks[last$1] = FieldMask.orMask(blockMasks[last$1], mask$1);
347
+ } else {
348
+ blockBlockNumbers.push(blockNumber);
349
+ blockMasks.push(mask$1);
350
+ blockItemGroups.push([item]);
351
+ }
352
+ });
353
+ return [
354
+ {
355
+ txBlockNumbers: txBlockNumbers,
356
+ transactionIndices: transactionIndices,
357
+ transactionMasks: transactionMasks,
358
+ payloadGroups: payloadGroups,
359
+ anyTransactionFieldSelected: anyTransactionFieldSelected.contents
360
+ },
361
+ {
362
+ blockBlockNumbers: blockBlockNumbers,
363
+ blockMasks: blockMasks,
364
+ blockItemGroups: blockItemGroups
365
+ }
366
+ ];
335
367
  }
336
368
 
337
- function materializePageItems(items, page) {
338
- if (page !== undefined) {
339
- return TransactionStore.materializeItems(Primitive_option.valFromOption(page), items);
340
- } else {
341
- return Promise.resolve();
369
+ async function applyTransactionGroups(store, g) {
370
+ if (!Utils.$$Array.notEmpty(g.payloadGroups)) {
371
+ return;
372
+ }
373
+ if (g.anyTransactionFieldSelected) {
374
+ let txs = await store.materialize(g.txBlockNumbers, g.transactionIndices, g.transactionMasks);
375
+ g.payloadGroups.forEach((payloads, i) => {
376
+ let tx = txs[i];
377
+ payloads.forEach(payload => {
378
+ payload.transaction = tx;
379
+ });
380
+ });
381
+ return;
382
+ }
383
+ g.payloadGroups.forEach(payloads => {
384
+ payloads.forEach(payload => {
385
+ payload.transaction = {};
386
+ });
387
+ });
388
+ }
389
+
390
+ async function applyBlockGroups(store, g) {
391
+ if (!Utils.$$Array.notEmpty(g.blockItemGroups)) {
392
+ return;
342
393
  }
394
+ let blocks = await store.materialize(g.blockBlockNumbers, g.blockMasks);
395
+ g.blockItemGroups.forEach((group, i) => {
396
+ let block = blocks[i];
397
+ group.forEach(ei => {
398
+ ei.payload.block = block;
399
+ });
400
+ });
401
+ }
402
+
403
+ function includeBlocksForEcosystem(ecosystem) {
404
+ switch (ecosystem) {
405
+ case "fuel" :
406
+ return false;
407
+ case "evm" :
408
+ case "svm" :
409
+ return true;
410
+ }
411
+ }
412
+
413
+ async function materializeBatchItems(cs, items, ecosystem) {
414
+ let match = groupBatchItems(items, includeBlocksForEcosystem(ecosystem));
415
+ await Promise.all([
416
+ applyTransactionGroups(cs.transactionStore, match[0]),
417
+ applyBlockGroups(cs.blockStore, match[1])
418
+ ]);
419
+ }
420
+
421
+ async function materializePageItems(items, transactionStore, blockStore, ecosystem) {
422
+ let match = groupBatchItems(items, includeBlocksForEcosystem(ecosystem));
423
+ await Promise.all([
424
+ transactionStore !== undefined ? applyTransactionGroups(Primitive_option.valFromOption(transactionStore), match[0]) : Promise.resolve(),
425
+ blockStore !== undefined ? applyBlockGroups(Primitive_option.valFromOption(blockStore), match[1]) : Promise.resolve()
426
+ ]);
343
427
  }
344
428
 
345
- function handleQueryResult(cs, query, newItems, newItemsWithDcs, latestFetchedBlock, knownHeight, page) {
346
- if (page !== undefined) {
347
- cs.transactionStore.merge(Primitive_option.valFromOption(page));
429
+ function handleQueryResult(cs, query, newItems, newItemsWithDcs, latestFetchedBlock, knownHeight, txPage, blockPage) {
430
+ if (txPage !== undefined) {
431
+ cs.transactionStore.merge(Primitive_option.valFromOption(txPage));
432
+ }
433
+ if (blockPage !== undefined) {
434
+ cs.blockStore.merge(Primitive_option.valFromOption(blockPage));
348
435
  }
349
436
  let fs = newItemsWithDcs.length !== 0 ? FetchState.registerDynamicContracts(cs.fetchState, cs.indexingAddresses, newItemsWithDcs) : cs.fetchState;
350
437
  cs.fetchState = FetchState.updateKnownHeight(FetchState.handleQueryResult(fs, cs.indexingAddresses, query, latestFetchedBlock, newItems), knownHeight);
351
- cs.pendingBudget = Primitive_float.max(0, cs.pendingBudget - query.estResponseSize);
438
+ cs.pendingBudget = Primitive_float.max(0, cs.pendingBudget - query.itemsTarget);
352
439
  }
353
440
 
354
441
  function registerReorgGuard(cs, blockHashes, knownHeight) {
@@ -387,7 +474,7 @@ function setEndBlockToFirstEvent(cs, blockNumber) {
387
474
  blockLag: init.blockLag,
388
475
  buffer: init.buffer,
389
476
  maxOnBlockBufferSize: init.maxOnBlockBufferSize,
390
- onBlockConfigs: init.onBlockConfigs,
477
+ onBlockRegistrations: init.onBlockRegistrations,
391
478
  knownHeight: init.knownHeight,
392
479
  firstEventBlock: init.firstEventBlock
393
480
  };
@@ -405,7 +492,7 @@ function setEndBlockToFirstEvent(cs, blockNumber) {
405
492
  blockLag: init$1.blockLag,
406
493
  buffer: init$1.buffer,
407
494
  maxOnBlockBufferSize: init$1.maxOnBlockBufferSize,
408
- onBlockConfigs: init$1.onBlockConfigs,
495
+ onBlockRegistrations: init$1.onBlockRegistrations,
409
496
  knownHeight: init$1.knownHeight,
410
497
  firstEventBlock: init$1.firstEventBlock
411
498
  };
@@ -465,7 +552,7 @@ function advanceAfterBatch(cs, batch, enteringReorgThreshold) {
465
552
  }
466
553
  }
467
554
 
468
- function applyBatchProgress(cs, batch) {
555
+ function applyBatchProgress(cs, batch, blockTimestampName) {
469
556
  let chainId = cs.chainConfig.id;
470
557
  let chainAfterBatch = batch.progressedChainsById[chainId];
471
558
  if (chainAfterBatch === undefined) {
@@ -477,9 +564,9 @@ function applyBatchProgress(cs, batch) {
477
564
  if (cs.numEventsProcessed !== chainAfterBatch.totalEventsProcessed) {
478
565
  Prometheus.ProgressEventsCount.set(chainAfterBatch.totalEventsProcessed, chainId);
479
566
  }
480
- let eventItem = Batch.findLastEventItem(batch, chainId);
481
- if (eventItem !== undefined) {
482
- let blockTimestampMs = eventItem.timestamp * 1000 | 0;
567
+ let blockTimestamp = Stdlib_Option.flatMap(Stdlib_Option.flatMap(Batch.findLastEventItem(batch, chainId), eventItem => Primitive_option.fromNullable(eventItem.payload.block)), block => block[blockTimestampName]);
568
+ if (blockTimestamp !== undefined) {
569
+ let blockTimestampMs = Primitive_option.valFromOption(blockTimestamp) * 1000 | 0;
483
570
  Prometheus.ProgressLatency.set((Date.now() | 0) - blockTimestampMs | 0, chainId);
484
571
  }
485
572
  let match = cs.fetchState.firstEventBlock;
@@ -498,15 +585,31 @@ function applyBatchProgress(cs, batch) {
498
585
  blockLag: init.blockLag,
499
586
  buffer: init.buffer,
500
587
  maxOnBlockBufferSize: init.maxOnBlockBufferSize,
501
- onBlockConfigs: init.onBlockConfigs,
588
+ onBlockRegistrations: init.onBlockRegistrations,
502
589
  knownHeight: init.knownHeight,
503
590
  firstEventBlock: firstEventBlock
504
591
  };
505
592
  }
506
593
  }
594
+ let deltaBlocks = chainAfterBatch.progressBlockNumber - cs.committedProgressBlockNumber | 0;
595
+ if (deltaBlocks > 0) {
596
+ let deltaEvents = chainAfterBatch.totalEventsProcessed - cs.numEventsProcessed;
597
+ let match$1 = cs.chainDensity;
598
+ let match$2 = deltaEvents > 0;
599
+ let exit = 0;
600
+ if (match$1 !== undefined || match$2) {
601
+ exit = 1;
602
+ }
603
+ if (exit === 1) {
604
+ let batchDensity = deltaEvents / deltaBlocks;
605
+ let oldDensity = cs.chainDensity;
606
+ cs.chainDensity = oldDensity !== undefined ? (oldDensity + batchDensity) / 2 : batchDensity;
607
+ }
608
+ }
507
609
  cs.committedProgressBlockNumber = chainAfterBatch.progressBlockNumber;
508
610
  cs.numEventsProcessed = chainAfterBatch.totalEventsProcessed;
509
611
  cs.transactionStore.prune(chainAfterBatch.progressBlockNumber);
612
+ cs.blockStore.prune(chainAfterBatch.progressBlockNumber);
510
613
  cs.isProgressAtHead = cs.isProgressAtHead || chainAfterBatch.isProgressAtHeadWhenBatchCreated;
511
614
  let safeCheckpointTracking = cs.safeCheckpointTracking;
512
615
  if (safeCheckpointTracking !== undefined) {
@@ -529,6 +632,7 @@ function rollback(cs, newProgressBlockNumber, eventsProcessedDiff, rollbackTarge
529
632
  cs.reorgDetection = ReorgDetection.rollbackToValidBlockNumber(cs.reorgDetection, rollbackTargetBlockNumber);
530
633
  cs.fetchState = FetchState.rollback(cs.fetchState, cs.indexingAddresses, rollbackTargetBlockNumber);
531
634
  cs.transactionStore.rollback(rollbackTargetBlockNumber);
635
+ cs.blockStore.rollback(rollbackTargetBlockNumber);
532
636
  cs.committedProgressBlockNumber = Primitive_int.min(cs.committedProgressBlockNumber, rollbackTargetBlockNumber);
533
637
  return;
534
638
  } else {
@@ -551,6 +655,7 @@ function rollback(cs, newProgressBlockNumber, eventsProcessedDiff, rollbackTarge
551
655
  }
552
656
  cs.fetchState = FetchState.rollback(cs.fetchState, cs.indexingAddresses, newProgressBlockNumber);
553
657
  cs.transactionStore.rollback(newProgressBlockNumber);
658
+ cs.blockStore.rollback(newProgressBlockNumber);
554
659
  cs.committedProgressBlockNumber = newProgressBlockNumber;
555
660
  cs.numEventsProcessed = newTotalEventsProcessed;
556
661
  }
@@ -576,7 +681,7 @@ export {
576
681
  bufferSize,
577
682
  bufferReadyCount,
578
683
  getProgressPercentage,
579
- getProgressPercentageAt,
684
+ chainDensity,
580
685
  hasReadyItem,
581
686
  isReadyToEnterReorgThreshold,
582
687
  getNextQuery,
@@ -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,12 @@ 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, ~budget: int) => FetchState.nextQuery
67
+ let getNextQuery: (t, ~chainTargetItems: float) => FetchState.nextQuery
66
68
  let dispatch: (
67
69
  t,
68
70
  ~executeQuery: FetchState.query => promise<unit>,
@@ -110,11 +112,18 @@ let handleQueryResult: (
110
112
  ~latestFetchedBlock: FetchState.blockNumberAndTimestamp,
111
113
  ~knownHeight: int,
112
114
  ~transactionStore: option<TransactionStore.t>,
115
+ ~blockStore: option<BlockStore.t>,
113
116
  ) => unit
114
- let materializeBatchItems: (t, ~items: array<Internal.item>) => promise<unit>
117
+ let materializeBatchItems: (
118
+ t,
119
+ ~items: array<Internal.item>,
120
+ ~ecosystem: Ecosystem.name,
121
+ ) => promise<unit>
115
122
  let materializePageItems: (
116
123
  ~items: array<Internal.item>,
117
- ~page: option<TransactionStore.t>,
124
+ ~transactionStore: option<TransactionStore.t>,
125
+ ~blockStore: option<BlockStore.t>,
126
+ ~ecosystem: Ecosystem.name,
118
127
  ) => promise<unit>
119
128
  let registerReorgGuard: (
120
129
  t,
@@ -126,7 +135,7 @@ let updateKnownHeight: (t, ~knownHeight: int) => unit
126
135
  let setEndBlockToFirstEvent: (t, ~blockNumber: int) => unit
127
136
  let enterReorgThreshold: t => unit
128
137
  let advanceAfterBatch: (t, ~batch: Batch.t, ~enteringReorgThreshold: bool) => unit
129
- let applyBatchProgress: (t, ~batch: Batch.t) => unit
138
+ let applyBatchProgress: (t, ~batch: Batch.t, ~blockTimestampName: string) => unit
130
139
  let markReady: t => unit
131
140
  let rollback: (
132
141
  t,