envio 3.3.0-alpha.0 → 3.3.0-alpha.10

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 (140) hide show
  1. package/evm.schema.json +10 -0
  2. package/index.d.ts +45 -25
  3. package/package.json +7 -7
  4. package/src/Address.res +5 -2
  5. package/src/Address.res.mjs +3 -1
  6. package/src/Api.res +1 -1
  7. package/src/Api.res.mjs +1 -1
  8. package/src/Batch.res +0 -6
  9. package/src/Batch.res.mjs +1 -12
  10. package/src/BatchProcessing.res +7 -12
  11. package/src/BatchProcessing.res.mjs +8 -7
  12. package/src/Bin.res +3 -0
  13. package/src/Bin.res.mjs +4 -0
  14. package/src/ChainFetching.res +48 -16
  15. package/src/ChainFetching.res.mjs +36 -17
  16. package/src/ChainMetadata.res +1 -11
  17. package/src/ChainMetadata.res.mjs +1 -10
  18. package/src/ChainState.res +628 -149
  19. package/src/ChainState.res.mjs +440 -102
  20. package/src/ChainState.resi +74 -4
  21. package/src/Config.res +61 -33
  22. package/src/Config.res.mjs +50 -10
  23. package/src/ContractRegisterContext.res +2 -12
  24. package/src/ContractRegisterContext.res.mjs +3 -5
  25. package/src/Core.res +14 -3
  26. package/src/CrossChainState.res +142 -93
  27. package/src/CrossChainState.res.mjs +88 -60
  28. package/src/CrossChainState.resi +2 -10
  29. package/src/Ecosystem.res +5 -6
  30. package/src/Ecosystem.res.mjs +3 -3
  31. package/src/Env.res +0 -7
  32. package/src/Env.res.mjs +0 -6
  33. package/src/Envio.res +17 -11
  34. package/src/EnvioGlobal.res +53 -0
  35. package/src/EnvioGlobal.res.mjs +31 -0
  36. package/src/EventConfigBuilder.res +177 -88
  37. package/src/EventConfigBuilder.res.mjs +99 -42
  38. package/src/EventProcessing.res +74 -28
  39. package/src/EventProcessing.res.mjs +55 -29
  40. package/src/ExitOnCaughtUp.res +10 -2
  41. package/src/ExitOnCaughtUp.res.mjs +10 -1
  42. package/src/FetchState.res +558 -300
  43. package/src/FetchState.res.mjs +437 -423
  44. package/src/HandlerLoader.res +8 -104
  45. package/src/HandlerLoader.res.mjs +2 -81
  46. package/src/HandlerRegister.res +518 -144
  47. package/src/HandlerRegister.res.mjs +285 -133
  48. package/src/HandlerRegister.resi +24 -8
  49. package/src/IndexerLoop.res +2 -3
  50. package/src/IndexerLoop.res.mjs +1 -1
  51. package/src/IndexerState.res +10 -11
  52. package/src/IndexerState.res.mjs +14 -11
  53. package/src/IndexerState.resi +2 -5
  54. package/src/IndexingAddresses.res +108 -0
  55. package/src/IndexingAddresses.res.mjs +101 -0
  56. package/src/IndexingAddresses.resi +34 -0
  57. package/src/Internal.res +155 -46
  58. package/src/Internal.res.mjs +30 -2
  59. package/src/LoadLayer.res +5 -5
  60. package/src/LoadLayer.res.mjs +6 -6
  61. package/src/LogSelection.res +102 -165
  62. package/src/LogSelection.res.mjs +101 -116
  63. package/src/Main.res +71 -236
  64. package/src/Main.res.mjs +60 -145
  65. package/src/Metrics.res +74 -0
  66. package/src/Metrics.res.mjs +75 -0
  67. package/src/PgStorage.res +4 -4
  68. package/src/PgStorage.res.mjs +5 -5
  69. package/src/Prometheus.res +10 -74
  70. package/src/Prometheus.res.mjs +124 -186
  71. package/src/PruneStaleHistory.res +2 -2
  72. package/src/PruneStaleHistory.res.mjs +3 -3
  73. package/src/RawEvent.res +7 -2
  74. package/src/RawEvent.res.mjs +4 -4
  75. package/src/Rollback.res +3 -3
  76. package/src/Rollback.res.mjs +4 -4
  77. package/src/RollbackCommit.res +4 -1
  78. package/src/RollbackCommit.res.mjs +3 -2
  79. package/src/SimulateDeadInputTracker.res +85 -0
  80. package/src/SimulateDeadInputTracker.res.mjs +73 -0
  81. package/src/SimulateDeadInputTracker.resi +12 -0
  82. package/src/SimulateItems.res +91 -23
  83. package/src/SimulateItems.res.mjs +55 -32
  84. package/src/TestIndexer.res +54 -40
  85. package/src/TestIndexer.res.mjs +37 -30
  86. package/src/bindings/Performance.res +7 -0
  87. package/src/bindings/Performance.res.mjs +21 -0
  88. package/src/bindings/Performance.resi +7 -0
  89. package/src/bindings/Viem.res +0 -41
  90. package/src/bindings/Viem.res.mjs +1 -43
  91. package/src/sources/BlockStore.res +46 -0
  92. package/src/sources/BlockStore.res.mjs +24 -0
  93. package/src/sources/EventRouter.res +36 -33
  94. package/src/sources/EventRouter.res.mjs +13 -14
  95. package/src/sources/Evm.res +83 -72
  96. package/src/sources/Evm.res.mjs +53 -69
  97. package/src/sources/EvmChain.res +18 -20
  98. package/src/sources/EvmChain.res.mjs +15 -15
  99. package/src/sources/EvmRpcClient.res +74 -5
  100. package/src/sources/EvmRpcClient.res.mjs +13 -4
  101. package/src/sources/FieldMask.res +39 -0
  102. package/src/sources/FieldMask.res.mjs +42 -0
  103. package/src/sources/Fuel.res +9 -6
  104. package/src/sources/Fuel.res.mjs +5 -10
  105. package/src/sources/HyperFuelSource.res +46 -50
  106. package/src/sources/HyperFuelSource.res.mjs +64 -54
  107. package/src/sources/HyperSync.res +39 -7
  108. package/src/sources/HyperSync.res.mjs +57 -37
  109. package/src/sources/HyperSync.resi +12 -2
  110. package/src/sources/HyperSyncClient.res +22 -111
  111. package/src/sources/HyperSyncClient.res.mjs +2 -30
  112. package/src/sources/HyperSyncHeightStream.res +1 -8
  113. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  114. package/src/sources/HyperSyncSource.res +94 -107
  115. package/src/sources/HyperSyncSource.res.mjs +82 -86
  116. package/src/sources/Rpc.res +15 -47
  117. package/src/sources/Rpc.res.mjs +25 -56
  118. package/src/sources/RpcSource.res +320 -467
  119. package/src/sources/RpcSource.res.mjs +268 -385
  120. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  121. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  122. package/src/sources/SimulateSource.res +10 -4
  123. package/src/sources/SimulateSource.res.mjs +16 -6
  124. package/src/sources/Source.res +34 -6
  125. package/src/sources/SourceManager.res +86 -27
  126. package/src/sources/SourceManager.res.mjs +84 -47
  127. package/src/sources/SourceManager.resi +12 -3
  128. package/src/sources/Svm.res +31 -16
  129. package/src/sources/Svm.res.mjs +36 -13
  130. package/src/sources/SvmHyperSyncClient.res +5 -32
  131. package/src/sources/SvmHyperSyncSource.res +159 -134
  132. package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
  133. package/src/sources/TransactionStore.res +49 -0
  134. package/src/sources/TransactionStore.res.mjs +30 -0
  135. package/src/tui/Tui.res +13 -16
  136. package/src/tui/Tui.res.mjs +12 -14
  137. package/svm.schema.json +49 -37
  138. package/src/bindings/Hrtime.res +0 -58
  139. package/src/bindings/Hrtime.res.mjs +0 -90
  140. package/src/bindings/Hrtime.resi +0 -30
@@ -2,35 +2,18 @@
2
2
 
3
3
  import * as Utils from "./Utils.res.mjs";
4
4
  import * as Logging from "./Logging.res.mjs";
5
+ import * as ChainMap from "./ChainMap.res.mjs";
6
+ import * as EnvioGlobal from "./EnvioGlobal.res.mjs";
7
+ import * as EventRouter from "./sources/EventRouter.res.mjs";
5
8
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
9
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
7
10
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
11
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
12
+ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
13
+ import * as EventConfigBuilder from "./EventConfigBuilder.res.mjs";
14
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
8
15
 
9
- let version = Utils.EnvioPackage.value.version;
10
-
11
- let existing = globalThis.__envioRegistry;
12
-
13
- let registry;
14
-
15
- if (existing == null) {
16
- let fresh_eventRegistrations = {};
17
- let fresh_activeRegistration = {
18
- contents: undefined
19
- };
20
- let fresh_preRegistered = [];
21
- let fresh = {
22
- version: version,
23
- eventRegistrations: fresh_eventRegistrations,
24
- activeRegistration: fresh_activeRegistration,
25
- preRegistered: fresh_preRegistered
26
- };
27
- globalThis.__envioRegistry = fresh;
28
- registry = fresh;
29
- } else {
30
- registry = existing.version === version ? existing : Stdlib_JsError.throwWithMessage(`Multiple incompatible envio versions loaded in the same process: ` + existing.version + ` and ` + version + `. Deduplicate the 'envio' dependency in your project.`);
31
- }
32
-
33
- let eventRegistrations = registry.eventRegistrations;
16
+ let eventRegistrations = EnvioGlobal.value.eventRegistrations;
34
17
 
35
18
  function getKey(contractName, eventName) {
36
19
  return contractName + "." + eventName;
@@ -53,12 +36,10 @@ function set(contractName, eventName, registration) {
53
36
  eventRegistrations[getKey(contractName, eventName)] = registration;
54
37
  }
55
38
 
56
- let activeRegistration = registry.activeRegistration;
57
-
58
- let preRegistered = registry.preRegistered;
39
+ let preRegistered = EnvioGlobal.value.preRegistered;
59
40
 
60
41
  function withRegistration(fn) {
61
- let r = activeRegistration.contents;
42
+ let r = EnvioGlobal.value.activeRegistration;
62
43
  if (r !== undefined) {
63
44
  if (r.finished) {
64
45
  return Stdlib_JsError.throwWithMessage("The indexer finished initializing, so no more handlers can be registered. Make sure the handlers are registered on the top level of the file.");
@@ -71,15 +52,13 @@ function withRegistration(fn) {
71
52
  }
72
53
  }
73
54
 
74
- function startRegistration(ecosystem) {
55
+ function startRegistration(config) {
75
56
  let r = {
76
- ecosystem: ecosystem,
77
- registrations: {
78
- onBlockByChainId: {}
79
- },
57
+ config: config,
58
+ registrationsByChainId: {},
80
59
  finished: false
81
60
  };
82
- activeRegistration.contents = r;
61
+ EnvioGlobal.value.activeRegistration = Primitive_option.some(r);
83
62
  while (preRegistered.length !== 0) {
84
63
  let fn = preRegistered.pop();
85
64
  if (fn !== undefined) {
@@ -88,51 +67,37 @@ function startRegistration(ecosystem) {
88
67
  };
89
68
  }
90
69
 
91
- function finishRegistration() {
92
- let r = activeRegistration.contents;
93
- if (r !== undefined) {
94
- r.finished = true;
95
- return r.registrations;
96
- } else {
97
- return Stdlib_JsError.throwWithMessage("The indexer has not started registering handlers, so can't finish it.");
98
- }
99
- }
100
-
101
- function isPendingRegistration() {
102
- let r = activeRegistration.contents;
103
- if (r !== undefined) {
104
- return !r.finished;
105
- } else {
106
- return false;
70
+ function getPendingChainRegistrations(r, chainId) {
71
+ let key = chainId.toString();
72
+ let pending = r.registrationsByChainId[key];
73
+ if (pending !== undefined) {
74
+ return pending;
107
75
  }
76
+ let fresh_onEventRegistrations = {};
77
+ let fresh_onBlockRegistrations = [];
78
+ let fresh = {
79
+ onEventRegistrations: fresh_onEventRegistrations,
80
+ onBlockRegistrations: fresh_onBlockRegistrations
81
+ };
82
+ r.registrationsByChainId[key] = fresh;
83
+ return fresh;
108
84
  }
109
85
 
110
- function throwIfFinishedRegistration(methodName) {
111
- let match = activeRegistration.contents;
112
- if (match === undefined) {
113
- return;
114
- }
115
- let match$1 = match.finished;
116
- if (match$1) {
117
- return Stdlib_JsError.throwWithMessage(`Cannot call \`indexer.` + methodName + `\` after the indexer has started. Make sure all handlers are registered at the top level of your handler module.`);
86
+ function buildOnEventRegistrationWith(config, chainId, eventConfig, isWildcard, handler, contractRegister, where, startBlock) {
87
+ let match = config.ecosystem.name;
88
+ switch (match) {
89
+ case "evm" :
90
+ return EventConfigBuilder.buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, chainId, config.ecosystem.onEventBlockFilterSchema, startBlock);
91
+ case "fuel" :
92
+ return EventConfigBuilder.buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock);
93
+ case "svm" :
94
+ return EventConfigBuilder.buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock);
118
95
  }
119
96
  }
120
97
 
121
- function registerOnBlock(name, chainId, interval, startBlock, endBlock, handler) {
122
- withRegistration(registration => {
123
- let onBlockByChainId = registration.registrations.onBlockByChainId;
124
- let key = chainId.toString();
125
- let index = Stdlib_Option.mapOr(onBlockByChainId[key], 0, configs => configs.length);
126
- Utils.Dict.push(onBlockByChainId, key, {
127
- index: index,
128
- name: name,
129
- chainId: chainId,
130
- startBlock: startBlock,
131
- endBlock: endBlock,
132
- interval: interval,
133
- handler: handler
134
- });
135
- });
98
+ function buildOnEventRegistration(config, chainId, eventConfig, startBlock) {
99
+ let t = get(eventConfig.contractName, eventConfig.name);
100
+ return buildOnEventRegistrationWith(config, chainId, eventConfig, Stdlib_Option.getOr(Stdlib_Option.flatMap(t.eventOptions, v => v.wildcard), false), t.handler, t.contractRegister, Stdlib_Option.flatMap(t.eventOptions, v => v.where), startBlock);
136
101
  }
137
102
 
138
103
  function getHandler(contractName, eventName) {
@@ -143,10 +108,6 @@ function getContractRegister(contractName, eventName) {
143
108
  return get(contractName, eventName).contractRegister;
144
109
  }
145
110
 
146
- function getOnEventWhere(contractName, eventName) {
147
- return Stdlib_Option.flatMap(get(contractName, eventName).eventOptions, value => value.where);
148
- }
149
-
150
111
  function isWildcard(contractName, eventName) {
151
112
  return Stdlib_Option.getOr(Stdlib_Option.flatMap(get(contractName, eventName).eventOptions, value => value.wildcard), false);
152
113
  }
@@ -171,22 +132,8 @@ function raiseDuplicateRegistration(contractName, eventName, msg, logger) {
171
132
 
172
133
  function eventOptionsMatch(existing, incoming) {
173
134
  if (existing !== undefined) {
174
- if (incoming !== undefined && existing.wildcard === incoming.wildcard) {
175
- let a = existing.where;
176
- let b = incoming.where;
177
- if (a !== undefined) {
178
- if (b !== undefined) {
179
- if (typeof a === "function" || typeof b === "function") {
180
- return a === b;
181
- } else {
182
- return Primitive_object.equal(a, b);
183
- }
184
- } else {
185
- return false;
186
- }
187
- } else {
188
- return b === undefined;
189
- }
135
+ if (incoming !== undefined) {
136
+ return existing.wildcard === incoming.wildcard;
190
137
  } else {
191
138
  return false;
192
139
  }
@@ -195,6 +142,31 @@ function eventOptionsMatch(existing, incoming) {
195
142
  }
196
143
  }
197
144
 
145
+ function syncOnEventRegistrations(r, contractName, eventName, where, duplicateMsg, logger) {
146
+ let config = r.config;
147
+ let t = get(contractName, eventName);
148
+ let isWildcard = Stdlib_Option.getOr(Stdlib_Option.flatMap(t.eventOptions, v => v.wildcard), false);
149
+ let key = getKey(contractName, eventName);
150
+ ChainMap.values(config.chainMap).forEach(chainConfig => {
151
+ chainConfig.contracts.forEach(contract => {
152
+ if (contract.name !== contractName) {
153
+ return;
154
+ }
155
+ let eventConfig = contract.events.find(e => e.name === eventName);
156
+ if (eventConfig === undefined) {
157
+ return;
158
+ }
159
+ let newRegistration = buildOnEventRegistrationWith(config, chainConfig.id, eventConfig, isWildcard, t.handler, t.contractRegister, where, contract.startBlock);
160
+ let pending = getPendingChainRegistrations(r, chainConfig.id);
161
+ let existing = pending.onEventRegistrations[key];
162
+ if (existing !== undefined && config.ecosystem.name === "evm" && !Primitive_object.equal(existing.resolvedWhere, newRegistration.resolvedWhere)) {
163
+ raiseDuplicateRegistration(contractName, eventName, duplicateMsg, logger);
164
+ }
165
+ pending.onEventRegistrations[key] = newRegistration;
166
+ });
167
+ });
168
+ }
169
+
198
170
  function setEventOptions(contractName, eventName, eventOptions, loggerOpt) {
199
171
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
200
172
  if (eventOptions === undefined) {
@@ -219,76 +191,256 @@ function setEventOptions(contractName, eventName, eventOptions, loggerOpt) {
219
191
 
220
192
  function setHandler(contractName, eventName, handler, eventOptions, loggerOpt) {
221
193
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
222
- withRegistration(_registration => {
194
+ withRegistration(registration => {
223
195
  let t = get(contractName, eventName);
196
+ let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
224
197
  let prevHandler = t.handler;
225
198
  if (prevHandler !== undefined) {
226
- let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
227
- if (!eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
228
- return raiseDuplicateRegistration(contractName, eventName, "Cannot register a second handler with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
199
+ if (eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
200
+ let composedHandler = async args => {
201
+ await prevHandler(args);
202
+ return await handler(args);
203
+ };
204
+ set(contractName, eventName, {
205
+ handler: composedHandler,
206
+ contractRegister: t.contractRegister,
207
+ eventOptions: t.eventOptions
208
+ });
209
+ } else {
210
+ raiseDuplicateRegistration(contractName, eventName, "Cannot register a second handler with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
229
211
  }
230
- let composedHandler = async args => {
231
- await prevHandler(args);
232
- return await handler(args);
233
- };
234
- return set(contractName, eventName, {
235
- handler: composedHandler,
236
- contractRegister: t.contractRegister,
237
- eventOptions: t.eventOptions
212
+ } else {
213
+ setEventOptions(contractName, eventName, eventOptions, logger);
214
+ let t$1 = get(contractName, eventName);
215
+ set(contractName, eventName, {
216
+ handler: handler,
217
+ contractRegister: t$1.contractRegister,
218
+ eventOptions: t$1.eventOptions
238
219
  });
239
220
  }
240
- setEventOptions(contractName, eventName, eventOptions, logger);
241
- let t$1 = get(contractName, eventName);
242
- set(contractName, eventName, {
243
- handler: handler,
244
- contractRegister: t$1.contractRegister,
245
- eventOptions: t$1.eventOptions
246
- });
221
+ syncOnEventRegistrations(registration, contractName, eventName, Stdlib_Option.flatMap(incomingEventOptions, v => v.where), "Cannot register a second handler with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
247
222
  });
248
223
  }
249
224
 
250
225
  function setContractRegister(contractName, eventName, contractRegister, eventOptions, loggerOpt) {
251
226
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
252
- withRegistration(_registration => {
227
+ withRegistration(registration => {
253
228
  let t = get(contractName, eventName);
229
+ let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
254
230
  let prevContractRegister = t.contractRegister;
255
231
  if (prevContractRegister !== undefined) {
256
- let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
257
- if (!eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
258
- return raiseDuplicateRegistration(contractName, eventName, "Cannot register a second contractRegister with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
232
+ if (eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
233
+ let composedContractRegister = async args => {
234
+ await prevContractRegister(args);
235
+ return await contractRegister(args);
236
+ };
237
+ set(contractName, eventName, {
238
+ handler: t.handler,
239
+ contractRegister: composedContractRegister,
240
+ eventOptions: t.eventOptions
241
+ });
242
+ } else {
243
+ raiseDuplicateRegistration(contractName, eventName, "Cannot register a second contractRegister with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
259
244
  }
260
- let composedContractRegister = async args => {
261
- await prevContractRegister(args);
262
- return await contractRegister(args);
263
- };
264
- return set(contractName, eventName, {
265
- handler: t.handler,
266
- contractRegister: composedContractRegister,
267
- eventOptions: t.eventOptions
245
+ } else {
246
+ setEventOptions(contractName, eventName, eventOptions, logger);
247
+ let t$1 = get(contractName, eventName);
248
+ set(contractName, eventName, {
249
+ handler: t$1.handler,
250
+ contractRegister: contractRegister,
251
+ eventOptions: t$1.eventOptions
268
252
  });
269
253
  }
270
- setEventOptions(contractName, eventName, eventOptions, logger);
271
- let t$1 = get(contractName, eventName);
272
- set(contractName, eventName, {
273
- handler: t$1.handler,
274
- contractRegister: contractRegister,
275
- eventOptions: t$1.eventOptions
254
+ syncOnEventRegistrations(registration, contractName, eventName, Stdlib_Option.flatMap(incomingEventOptions, v => v.where), "Cannot register a second contractRegister with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
255
+ });
256
+ }
257
+
258
+ let blockRangeSchema = S$RescriptSchema.strict(S$RescriptSchema.object(s => ({
259
+ _gte: s.f("_gte", S$RescriptSchema.option(S$RescriptSchema.int)),
260
+ _lte: s.f("_lte", S$RescriptSchema.option(S$RescriptSchema.int)),
261
+ _every: s.f("_every", S$RescriptSchema.Option.getOr(S$RescriptSchema.option(S$RescriptSchema.intMin(S$RescriptSchema.int, 1, undefined)), 1))
262
+ })));
263
+
264
+ let defaultBlockRange = {
265
+ _gte: undefined,
266
+ _lte: undefined,
267
+ _every: 1
268
+ };
269
+
270
+ function extractRange(filter, name, ecosystem) {
271
+ try {
272
+ let inner = S$RescriptSchema.parseOrThrow(filter, ecosystem.onBlockFilterSchema);
273
+ if (inner !== undefined) {
274
+ return S$RescriptSchema.parseOrThrow(Primitive_option.valFromOption(inner), blockRangeSchema);
275
+ } else {
276
+ return defaultBlockRange;
277
+ }
278
+ } catch (raw_exn) {
279
+ let exn = Primitive_exceptions.internalToException(raw_exn);
280
+ if (exn.RE_EXN_ID === S$RescriptSchema.Raised) {
281
+ return Stdlib_JsError.throwWithMessage(`\`indexer.` + ecosystem.onBlockMethodName + `("` + name + `")\` \`where\` returned an invalid filter: ` + Utils.prettifyExn(exn._1));
282
+ }
283
+ throw exn;
284
+ }
285
+ }
286
+
287
+ function registerOnBlock(name, where, handler, getChainsObject) {
288
+ withRegistration(registration => {
289
+ let config = registration.config;
290
+ let ecosystem = config.ecosystem;
291
+ let chainsDict = getChainsObject(config);
292
+ let logger = Logging.createChild({
293
+ onBlock: name
276
294
  });
295
+ let where$1 = where === undefined || where === null ? undefined : (
296
+ typeof where === "function" ? where : Stdlib_JsError.throwWithMessage(`\`indexer.` + ecosystem.onBlockMethodName + `("` + name + `")\` expected \`where\` to be a function or omitted, but got ` + typeof where + `.`)
297
+ );
298
+ let matchedAny = {
299
+ contents: false
300
+ };
301
+ ChainMap.values(config.chainMap).forEach(chainConfig => {
302
+ let chainId = chainConfig.id;
303
+ let chainObj = chainsDict[chainId.toString()];
304
+ let result = where$1 !== undefined ? where$1({
305
+ chain: chainObj
306
+ }) : true;
307
+ let match = result === true ? [
308
+ true,
309
+ defaultBlockRange
310
+ ] : (
311
+ result === false ? [
312
+ false,
313
+ defaultBlockRange
314
+ ] : (
315
+ typeof result === "object" && !Array.isArray(result) && result !== null ? [
316
+ true,
317
+ extractRange(result, name, ecosystem)
318
+ ] : Stdlib_JsError.throwWithMessage(`\`indexer.` + ecosystem.onBlockMethodName + `("` + name + `")\` \`where\` predicate returned an invalid value of type ` + typeof result + `. Expected boolean or a filter object.`)
319
+ )
320
+ );
321
+ if (!match[0]) {
322
+ return;
323
+ }
324
+ let range = match[1];
325
+ matchedAny.contents = true;
326
+ if (Stdlib_Option.getOr(range._gte, chainConfig.startBlock) < chainConfig.startBlock) {
327
+ Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + name + `" is less than the chain start block (` + chainConfig.startBlock.toString() + `). This is not supported yet.`);
328
+ }
329
+ let chainEndBlock = chainConfig.endBlock;
330
+ if (chainEndBlock !== undefined && Stdlib_Option.getOr(range._lte, chainEndBlock) > chainEndBlock) {
331
+ Stdlib_JsError.throwWithMessage(`The end block for onBlock handler "` + name + `" is greater than the chain end block (` + chainEndBlock.toString() + `). This is not supported yet.`);
332
+ }
333
+ let pending = getPendingChainRegistrations(registration, chainId);
334
+ pending.onBlockRegistrations.push({
335
+ index: pending.onBlockRegistrations.length,
336
+ name: name,
337
+ chainId: chainId,
338
+ startBlock: range._gte,
339
+ endBlock: range._lte,
340
+ interval: range._every,
341
+ handler: handler
342
+ });
343
+ });
344
+ if (!matchedAny.contents) {
345
+ return Logging.childWarn(logger, `\`indexer.` + ecosystem.onBlockMethodName + `\` matched 0 chains. Check the \`where\` predicate.`);
346
+ }
277
347
  });
278
348
  }
279
349
 
350
+ function finishRegistration(config) {
351
+ let r = EnvioGlobal.value.activeRegistration;
352
+ if (r === undefined) {
353
+ return Stdlib_JsError.throwWithMessage("The indexer has not started registering handlers, so can't finish it.");
354
+ }
355
+ r.finished = true;
356
+ let notRegisteredEventsByContract = {};
357
+ let registrationsByChainId = {};
358
+ ChainMap.values(config.chainMap).forEach(chainConfig => {
359
+ let key = chainConfig.id.toString();
360
+ let pending = r.registrationsByChainId[key];
361
+ let eventRouter = EventRouter.empty();
362
+ let onEventRegistrations = [];
363
+ chainConfig.contracts.forEach(contract => {
364
+ let contractName = contract.name;
365
+ contract.events.forEach(eventConfig => {
366
+ let eventName = eventConfig.name;
367
+ let registration = Stdlib_Option.flatMap(pending, pending => pending.onEventRegistrations[getKey(contractName, eventName)]);
368
+ EventRouter.addOrThrow(eventRouter, eventConfig.id, undefined, contractName, registration !== undefined ? registration.isWildcard : isWildcard(contractName, eventName), eventName, ChainMap.Chain.makeUnsafe(chainConfig.id));
369
+ let registration$1;
370
+ if (registration !== undefined) {
371
+ registration$1 = registration;
372
+ } else if (hasRegistration(contractName, eventName) || config.enableRawEvents) {
373
+ registration$1 = buildOnEventRegistration(config, chainConfig.id, eventConfig, contract.startBlock);
374
+ } else {
375
+ let set = notRegisteredEventsByContract[contractName];
376
+ let eventNames;
377
+ if (set !== undefined) {
378
+ eventNames = Primitive_option.valFromOption(set);
379
+ } else {
380
+ let set$1 = new Set();
381
+ notRegisteredEventsByContract[contractName] = set$1;
382
+ eventNames = set$1;
383
+ }
384
+ eventNames.add(eventName);
385
+ registration$1 = undefined;
386
+ }
387
+ if (registration$1 === undefined) {
388
+ return;
389
+ }
390
+ let isDroppedByWhere = config.ecosystem.name === "evm" && Utils.$$Array.isEmpty(registration$1.resolvedWhere.topicSelections);
391
+ if (!isDroppedByWhere) {
392
+ onEventRegistrations.push(registration$1);
393
+ return;
394
+ }
395
+ });
396
+ });
397
+ registrationsByChainId[key] = {
398
+ onEventRegistrations: onEventRegistrations,
399
+ onBlockRegistrations: pending !== undefined ? pending.onBlockRegistrations : []
400
+ };
401
+ });
402
+ let notRegisteredEntries = Object.entries(notRegisteredEventsByContract);
403
+ if (Utils.$$Array.notEmpty(notRegisteredEntries)) {
404
+ let groups = notRegisteredEntries.map(param => param[0] + ` (` + Array.from(param[1]).join(", ") + `)`).join(", ");
405
+ Logging.childInfo(Logging.getLogger(), `Events without a handler, skipped for indexing: ` + groups);
406
+ }
407
+ return registrationsByChainId;
408
+ }
409
+
410
+ function isPendingRegistration() {
411
+ let r = EnvioGlobal.value.activeRegistration;
412
+ if (r !== undefined) {
413
+ return !r.finished;
414
+ } else {
415
+ return false;
416
+ }
417
+ }
418
+
419
+ function throwIfFinishedRegistration(methodName) {
420
+ let match = EnvioGlobal.value.activeRegistration;
421
+ if (match === undefined) {
422
+ return;
423
+ }
424
+ let match$1 = match.finished;
425
+ if (match$1) {
426
+ return Stdlib_JsError.throwWithMessage(`Cannot call \`indexer.` + methodName + `\` after the indexer has started. Make sure all handlers are registered at the top level of your handler module.`);
427
+ }
428
+ }
429
+
280
430
  export {
281
431
  startRegistration,
282
432
  isPendingRegistration,
283
433
  finishRegistration,
284
434
  throwIfFinishedRegistration,
435
+ buildOnEventRegistration,
285
436
  setHandler,
286
437
  setContractRegister,
287
438
  getHandler,
288
439
  getContractRegister,
289
- getOnEventWhere,
290
440
  isWildcard,
291
441
  hasRegistration,
442
+ blockRangeSchema,
443
+ defaultBlockRange,
292
444
  registerOnBlock,
293
445
  }
294
- /* existing Not a pure module */
446
+ /* blockRangeSchema Not a pure module */
@@ -1,10 +1,21 @@
1
- type registrations = {onBlockByChainId: dict<array<Internal.onBlockConfig>>}
1
+ type chainRegistrations = {
2
+ onEventRegistrations: array<Internal.onEventRegistration>,
3
+ onBlockRegistrations: array<Internal.onBlockRegistration>,
4
+ }
5
+ type registrationsByChainId = dict<chainRegistrations>
2
6
 
3
- let startRegistration: (~ecosystem: Ecosystem.t) => unit
7
+ let startRegistration: (~config: Config.t) => unit
4
8
  let isPendingRegistration: unit => bool
5
- let finishRegistration: unit => registrations
9
+ let finishRegistration: (~config: Config.t) => registrationsByChainId
6
10
  let throwIfFinishedRegistration: (~methodName: string) => unit
7
11
 
12
+ let buildOnEventRegistration: (
13
+ ~config: Config.t,
14
+ ~chainId: int,
15
+ ~eventConfig: Internal.eventConfig,
16
+ ~startBlock: int=?,
17
+ ) => Internal.onEventRegistration
18
+
8
19
  let setHandler: (
9
20
  ~contractName: string,
10
21
  ~eventName: string,
@@ -24,15 +35,20 @@ let getContractRegister: (
24
35
  ~contractName: string,
25
36
  ~eventName: string,
26
37
  ) => option<Internal.contractRegister>
27
- let getOnEventWhere: (~contractName: string, ~eventName: string) => option<JSON.t>
28
38
  let isWildcard: (~contractName: string, ~eventName: string) => bool
29
39
  let hasRegistration: (~contractName: string, ~eventName: string) => bool
30
40
 
41
+ type blockRange = {
42
+ _gte: option<int>,
43
+ _lte: option<int>,
44
+ _every: int,
45
+ }
46
+ let blockRangeSchema: S.t<blockRange>
47
+ let defaultBlockRange: blockRange
48
+
31
49
  let registerOnBlock: (
32
50
  ~name: string,
33
- ~chainId: int,
34
- ~interval: int,
35
- ~startBlock: option<int>,
36
- ~endBlock: option<int>,
51
+ ~where: unknown,
37
52
  ~handler: Internal.onBlockArgs => promise<unit>,
53
+ ~getChainsObject: Config.t => dict<unknown>,
38
54
  ) => unit
@@ -19,12 +19,11 @@ let start = (state: IndexerState.t) => {
19
19
  launch(state, () =>
20
20
  state
21
21
  ->IndexerState.crossChainState
22
- ->CrossChainState.checkAndFetch(~fetchChain=(~chain, ~concurrencyLimit, ~bufferLimit) =>
22
+ ->CrossChainState.checkAndFetch(~dispatchChain=(~chain, ~action) =>
23
23
  ChainFetching.fetchChain(
24
24
  state,
25
25
  chain,
26
- ~concurrencyLimit,
27
- ~bufferLimit,
26
+ ~action,
28
27
  ~stateId=state->IndexerState.epoch,
29
28
  ~scheduleFetch,
30
29
  ~scheduleProcessing,
@@ -15,7 +15,7 @@ function launch(state, work) {
15
15
 
16
16
  function start(state) {
17
17
  let scheduleFetch = () => {
18
- let work = () => CrossChainState.checkAndFetch(IndexerState.crossChainState(state), (chain, concurrencyLimit, bufferLimit) => ChainFetching.fetchChain(state, chain, concurrencyLimit, bufferLimit, IndexerState.epoch(state), scheduleFetch, scheduleProcessing, scheduleRollback));
18
+ let work = () => CrossChainState.checkAndFetch(IndexerState.crossChainState(state), (chain, action) => ChainFetching.fetchChain(state, chain, action, IndexerState.epoch(state), scheduleFetch, scheduleProcessing, scheduleRollback));
19
19
  if (!IndexerState.isStopped(state)) {
20
20
  work();
21
21
  return;
@@ -108,6 +108,8 @@ type t = {
108
108
  // waitForNewBlock waiter is bound to the old, pre-realtime source). A fetch
109
109
  // response or waiter carrying an older epoch than this is discarded.
110
110
  mutable epoch: int,
111
+ // None off the simulate path.
112
+ simulateDeadInputTracker: option<SimulateDeadInputTracker.t>,
111
113
  }
112
114
 
113
115
  let make = (
@@ -116,8 +118,6 @@ let make = (
116
118
  ~chainStates: dict<ChainState.t>,
117
119
  ~isInReorgThreshold: bool,
118
120
  ~isRealtime: bool,
119
- ~maxBackfillConcurrency=Env.maxBackfillConcurrency,
120
- ~maxRealtimeConcurrency=Env.maxRealtimeConcurrency,
121
121
  ~targetBufferSize=CrossChainState.calculateTargetBufferSize(),
122
122
  ~committedCheckpointId=Internal.initialCheckpointId,
123
123
  ~isDevelopmentMode=false,
@@ -160,8 +160,6 @@ let make = (
160
160
  ~chainStates,
161
161
  ~isInReorgThreshold,
162
162
  ~isRealtime,
163
- ~maxBackfillConcurrency,
164
- ~maxRealtimeConcurrency,
165
163
  ~targetBufferSize,
166
164
  ),
167
165
  indexerStartTime: Date.make(),
@@ -173,6 +171,7 @@ let make = (
173
171
  onError,
174
172
  isStopped: false,
175
173
  epoch: 0,
174
+ simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config),
176
175
  }
177
176
  }
178
177
 
@@ -189,13 +188,11 @@ let makeFromDbState = (
189
188
  ~config: Config.t,
190
189
  ~persistence: Persistence.t,
191
190
  ~initialState: Persistence.initialState,
192
- ~registrations,
191
+ ~registrationsByChainId,
193
192
  ~isDevelopmentMode=false,
194
193
  ~shouldUseTui=false,
195
194
  ~exitAfterFirstEventBlock=false,
196
195
  ~reducedPollingInterval=?,
197
- ~maxBackfillConcurrency=Env.maxBackfillConcurrency,
198
- ~maxRealtimeConcurrency=Env.maxRealtimeConcurrency,
199
196
  ~targetBufferSize=CrossChainState.calculateTargetBufferSize(),
200
197
  ~onError,
201
198
  ) => {
@@ -237,7 +234,7 @@ let makeFromDbState = (
237
234
  ~isInReorgThreshold,
238
235
  ~isRealtime,
239
236
  ~config,
240
- ~registrations,
237
+ ~registrationsByChainId,
241
238
  ~reducedPollingInterval?,
242
239
  ),
243
240
  )
@@ -269,8 +266,6 @@ let makeFromDbState = (
269
266
  ~chainStates,
270
267
  ~isInReorgThreshold,
271
268
  ~isRealtime,
272
- ~maxBackfillConcurrency,
273
- ~maxRealtimeConcurrency,
274
269
  ~targetBufferSize,
275
270
  ~committedCheckpointId=initialState.checkpointId,
276
271
  ~isDevelopmentMode,
@@ -367,7 +362,10 @@ let clearRollback = (state: t) => state.rollbackState = NoRollback
367
362
  let invalidateInflight = (state: t) => state.epoch = state.epoch + 1
368
363
 
369
364
  let applyBatchProgress = (state: t, ~batch: Batch.t) =>
370
- state.crossChainState->CrossChainState.applyBatchProgress(~batch)
365
+ state.crossChainState->CrossChainState.applyBatchProgress(
366
+ ~batch,
367
+ ~blockTimestampName=state.config.ecosystem.blockTimestampName,
368
+ )
371
369
 
372
370
  // Processing-loop mutex. Guards ProcessEventBatch re-entry so only one
373
371
  // processing loop runs at a time.
@@ -408,6 +406,7 @@ let exitAfterFirstEventBlock = (state: t) => state.exitAfterFirstEventBlock
408
406
  let isStopped = (state: t) => state.isStopped
409
407
  let epoch = (state: t) => state.epoch
410
408
  let pruneStaleEntityHistoryThrottler = (state: t) => state.writeThrottlers.pruneStaleEntityHistory
409
+ let simulateDeadInputTracker = (state: t) => state.simulateDeadInputTracker
411
410
 
412
411
  // --- Store domain operations. ---
413
412