envio 3.3.0-alpha.1 → 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 (136) 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 +43 -9
  15. package/src/ChainFetching.res.mjs +34 -15
  16. package/src/ChainMetadata.res +1 -11
  17. package/src/ChainMetadata.res.mjs +1 -10
  18. package/src/ChainState.res +605 -151
  19. package/src/ChainState.res.mjs +427 -104
  20. package/src/ChainState.resi +72 -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 +113 -89
  27. package/src/CrossChainState.res.mjs +64 -60
  28. package/src/CrossChainState.resi +1 -1
  29. package/src/Ecosystem.res +5 -6
  30. package/src/Ecosystem.res.mjs +3 -3
  31. package/src/Envio.res +17 -11
  32. package/src/EnvioGlobal.res +53 -0
  33. package/src/EnvioGlobal.res.mjs +31 -0
  34. package/src/EventConfigBuilder.res +177 -88
  35. package/src/EventConfigBuilder.res.mjs +99 -42
  36. package/src/EventProcessing.res +74 -28
  37. package/src/EventProcessing.res.mjs +55 -29
  38. package/src/ExitOnCaughtUp.res +10 -2
  39. package/src/ExitOnCaughtUp.res.mjs +10 -1
  40. package/src/FetchState.res +544 -356
  41. package/src/FetchState.res.mjs +412 -471
  42. package/src/HandlerLoader.res +8 -104
  43. package/src/HandlerLoader.res.mjs +2 -81
  44. package/src/HandlerRegister.res +518 -144
  45. package/src/HandlerRegister.res.mjs +285 -133
  46. package/src/HandlerRegister.resi +24 -8
  47. package/src/IndexerState.res +10 -3
  48. package/src/IndexerState.res.mjs +11 -4
  49. package/src/IndexerState.resi +2 -1
  50. package/src/IndexingAddresses.res +108 -0
  51. package/src/IndexingAddresses.res.mjs +101 -0
  52. package/src/IndexingAddresses.resi +34 -0
  53. package/src/Internal.res +155 -46
  54. package/src/Internal.res.mjs +30 -2
  55. package/src/LoadLayer.res +5 -5
  56. package/src/LoadLayer.res.mjs +6 -6
  57. package/src/LogSelection.res +102 -165
  58. package/src/LogSelection.res.mjs +101 -116
  59. package/src/Main.res +71 -236
  60. package/src/Main.res.mjs +60 -145
  61. package/src/Metrics.res +74 -0
  62. package/src/Metrics.res.mjs +75 -0
  63. package/src/PgStorage.res +4 -4
  64. package/src/PgStorage.res.mjs +5 -5
  65. package/src/Prometheus.res +10 -63
  66. package/src/Prometheus.res.mjs +124 -171
  67. package/src/PruneStaleHistory.res +2 -2
  68. package/src/PruneStaleHistory.res.mjs +3 -3
  69. package/src/RawEvent.res +7 -2
  70. package/src/RawEvent.res.mjs +4 -4
  71. package/src/Rollback.res +3 -3
  72. package/src/Rollback.res.mjs +4 -4
  73. package/src/RollbackCommit.res +4 -1
  74. package/src/RollbackCommit.res.mjs +3 -2
  75. package/src/SimulateDeadInputTracker.res +85 -0
  76. package/src/SimulateDeadInputTracker.res.mjs +73 -0
  77. package/src/SimulateDeadInputTracker.resi +12 -0
  78. package/src/SimulateItems.res +91 -23
  79. package/src/SimulateItems.res.mjs +55 -32
  80. package/src/TestIndexer.res +54 -40
  81. package/src/TestIndexer.res.mjs +37 -30
  82. package/src/bindings/Performance.res +7 -0
  83. package/src/bindings/Performance.res.mjs +21 -0
  84. package/src/bindings/Performance.resi +7 -0
  85. package/src/bindings/Viem.res +0 -41
  86. package/src/bindings/Viem.res.mjs +1 -43
  87. package/src/sources/BlockStore.res +46 -0
  88. package/src/sources/BlockStore.res.mjs +24 -0
  89. package/src/sources/EventRouter.res +36 -33
  90. package/src/sources/EventRouter.res.mjs +13 -14
  91. package/src/sources/Evm.res +83 -72
  92. package/src/sources/Evm.res.mjs +53 -69
  93. package/src/sources/EvmChain.res +18 -20
  94. package/src/sources/EvmChain.res.mjs +15 -15
  95. package/src/sources/EvmRpcClient.res +74 -5
  96. package/src/sources/EvmRpcClient.res.mjs +13 -4
  97. package/src/sources/FieldMask.res +39 -0
  98. package/src/sources/FieldMask.res.mjs +42 -0
  99. package/src/sources/Fuel.res +9 -6
  100. package/src/sources/Fuel.res.mjs +5 -10
  101. package/src/sources/HyperFuelSource.res +46 -50
  102. package/src/sources/HyperFuelSource.res.mjs +64 -54
  103. package/src/sources/HyperSync.res +39 -7
  104. package/src/sources/HyperSync.res.mjs +57 -37
  105. package/src/sources/HyperSync.resi +12 -2
  106. package/src/sources/HyperSyncClient.res +22 -111
  107. package/src/sources/HyperSyncClient.res.mjs +2 -30
  108. package/src/sources/HyperSyncHeightStream.res +1 -8
  109. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  110. package/src/sources/HyperSyncSource.res +94 -107
  111. package/src/sources/HyperSyncSource.res.mjs +82 -86
  112. package/src/sources/Rpc.res +15 -47
  113. package/src/sources/Rpc.res.mjs +25 -56
  114. package/src/sources/RpcSource.res +320 -467
  115. package/src/sources/RpcSource.res.mjs +268 -385
  116. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  117. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  118. package/src/sources/SimulateSource.res +10 -4
  119. package/src/sources/SimulateSource.res.mjs +16 -6
  120. package/src/sources/Source.res +34 -6
  121. package/src/sources/SourceManager.res +77 -19
  122. package/src/sources/SourceManager.res.mjs +63 -21
  123. package/src/sources/SourceManager.resi +10 -0
  124. package/src/sources/Svm.res +31 -16
  125. package/src/sources/Svm.res.mjs +36 -13
  126. package/src/sources/SvmHyperSyncClient.res +5 -32
  127. package/src/sources/SvmHyperSyncSource.res +159 -134
  128. package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
  129. package/src/sources/TransactionStore.res +49 -0
  130. package/src/sources/TransactionStore.res.mjs +30 -0
  131. package/src/tui/Tui.res +13 -16
  132. package/src/tui/Tui.res.mjs +12 -14
  133. package/svm.schema.json +49 -37
  134. package/src/bindings/Hrtime.res +0 -58
  135. package/src/bindings/Hrtime.res.mjs +0 -90
  136. 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
@@ -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 = (
@@ -169,6 +171,7 @@ let make = (
169
171
  onError,
170
172
  isStopped: false,
171
173
  epoch: 0,
174
+ simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config),
172
175
  }
173
176
  }
174
177
 
@@ -185,7 +188,7 @@ let makeFromDbState = (
185
188
  ~config: Config.t,
186
189
  ~persistence: Persistence.t,
187
190
  ~initialState: Persistence.initialState,
188
- ~registrations,
191
+ ~registrationsByChainId,
189
192
  ~isDevelopmentMode=false,
190
193
  ~shouldUseTui=false,
191
194
  ~exitAfterFirstEventBlock=false,
@@ -231,7 +234,7 @@ let makeFromDbState = (
231
234
  ~isInReorgThreshold,
232
235
  ~isRealtime,
233
236
  ~config,
234
- ~registrations,
237
+ ~registrationsByChainId,
235
238
  ~reducedPollingInterval?,
236
239
  ),
237
240
  )
@@ -359,7 +362,10 @@ let clearRollback = (state: t) => state.rollbackState = NoRollback
359
362
  let invalidateInflight = (state: t) => state.epoch = state.epoch + 1
360
363
 
361
364
  let applyBatchProgress = (state: t, ~batch: Batch.t) =>
362
- state.crossChainState->CrossChainState.applyBatchProgress(~batch)
365
+ state.crossChainState->CrossChainState.applyBatchProgress(
366
+ ~batch,
367
+ ~blockTimestampName=state.config.ecosystem.blockTimestampName,
368
+ )
363
369
 
364
370
  // Processing-loop mutex. Guards ProcessEventBatch re-entry so only one
365
371
  // processing loop runs at a time.
@@ -400,6 +406,7 @@ let exitAfterFirstEventBlock = (state: t) => state.exitAfterFirstEventBlock
400
406
  let isStopped = (state: t) => state.isStopped
401
407
  let epoch = (state: t) => state.epoch
402
408
  let pruneStaleEntityHistoryThrottler = (state: t) => state.writeThrottlers.pruneStaleEntityHistory
409
+ let simulateDeadInputTracker = (state: t) => state.simulateDeadInputTracker
403
410
 
404
411
  // --- Store domain operations. ---
405
412
 
@@ -18,6 +18,7 @@ import * as CrossChainState from "./CrossChainState.res.mjs";
18
18
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
19
19
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
20
20
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
21
+ import * as SimulateDeadInputTracker from "./SimulateDeadInputTracker.res.mjs";
21
22
 
22
23
  function make() {
23
24
  let intervalMillis = Env.ThrottleWrites.pruneStaleDataIntervalMillis;
@@ -91,11 +92,12 @@ function make$2(config, persistence, chainStates, isInReorgThreshold, isRealtime
91
92
  exitAfterFirstEventBlock: exitAfterFirstEventBlock,
92
93
  onError: onError,
93
94
  isStopped: false,
94
- epoch: 0
95
+ epoch: 0,
96
+ simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config)
95
97
  };
96
98
  }
97
99
 
98
- function makeFromDbState(config, persistence, initialState, registrations, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, reducedPollingInterval, targetBufferSizeOpt, onError) {
100
+ function makeFromDbState(config, persistence, initialState, registrationsByChainId, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, reducedPollingInterval, targetBufferSizeOpt, onError) {
99
101
  let isDevelopmentMode = isDevelopmentModeOpt !== undefined ? isDevelopmentModeOpt : false;
100
102
  let shouldUseTui = shouldUseTuiOpt !== undefined ? shouldUseTuiOpt : false;
101
103
  let exitAfterFirstEventBlock = exitAfterFirstEventBlockOpt !== undefined ? exitAfterFirstEventBlockOpt : false;
@@ -121,7 +123,7 @@ function makeFromDbState(config, persistence, initialState, registrations, isDev
121
123
  initialState.chains.forEach(resumedChainState => {
122
124
  let chain = Config.getChain(config, resumedChainState.id);
123
125
  let chainConfig = ChainMap.get(config.chainMap, chain);
124
- chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrations, reducedPollingInterval);
126
+ chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval);
125
127
  });
126
128
  let allChainsReady = {
127
129
  contents: initialState.chains.length !== 0
@@ -229,7 +231,7 @@ function invalidateInflight(state) {
229
231
  }
230
232
 
231
233
  function applyBatchProgress(state, batch) {
232
- CrossChainState.applyBatchProgress(state.crossChainState, batch);
234
+ CrossChainState.applyBatchProgress(state.crossChainState, batch, state.config.ecosystem.blockTimestampName);
233
235
  }
234
236
 
235
237
  function isProcessing(state) {
@@ -348,6 +350,10 @@ function pruneStaleEntityHistoryThrottler(state) {
348
350
  return state.writeThrottlers.pruneStaleEntityHistory;
349
351
  }
350
352
 
353
+ function simulateDeadInputTracker(state) {
354
+ return state.simulateDeadInputTracker;
355
+ }
356
+
351
357
  function queueProcessedBatch(state, batch) {
352
358
  state.processedBatches.push(batch);
353
359
  let checkpointId = Utils.$$Array.last(batch.checkpointIds);
@@ -527,6 +533,7 @@ export {
527
533
  isStopped,
528
534
  epoch,
529
535
  pruneStaleEntityHistoryThrottler,
536
+ simulateDeadInputTracker,
530
537
  queueProcessedBatch,
531
538
  drainBatchRun,
532
539
  takeRollback,