envio 3.3.0-alpha.7 → 3.3.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +23 -5
- package/package.json +6 -6
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/ChainFetching.res +21 -10
- package/src/ChainFetching.res.mjs +11 -10
- package/src/ChainState.res +401 -171
- package/src/ChainState.res.mjs +270 -104
- package/src/ChainState.resi +19 -7
- package/src/Config.res +11 -27
- package/src/Config.res.mjs +8 -7
- package/src/Core.res +7 -0
- package/src/CrossChainState.res +82 -82
- package/src/CrossChainState.res.mjs +52 -59
- package/src/CrossChainState.resi +1 -1
- package/src/Ecosystem.res +3 -3
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Envio.res +14 -9
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +117 -69
- package/src/EventConfigBuilder.res.mjs +71 -34
- package/src/EventProcessing.res +19 -15
- package/src/EventProcessing.res.mjs +13 -12
- package/src/FetchState.res +410 -185
- package/src/FetchState.res.mjs +268 -253
- package/src/HandlerLoader.res +8 -113
- package/src/HandlerLoader.res.mjs +2 -88
- package/src/HandlerRegister.res +518 -144
- package/src/HandlerRegister.res.mjs +285 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerState.res +6 -3
- package/src/IndexerState.res.mjs +3 -3
- package/src/IndexerState.resi +1 -1
- package/src/IndexingAddresses.res +10 -7
- package/src/IndexingAddresses.res.mjs +8 -7
- package/src/IndexingAddresses.resi +3 -1
- package/src/Internal.res +104 -39
- package/src/Internal.res.mjs +11 -1
- package/src/LogSelection.res +102 -165
- package/src/LogSelection.res.mjs +101 -116
- package/src/Main.res +49 -164
- package/src/Main.res.mjs +39 -104
- package/src/Metrics.res +43 -2
- package/src/Metrics.res.mjs +39 -3
- package/src/Prometheus.res +0 -35
- package/src/Prometheus.res.mjs +33 -68
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateItems.res +20 -7
- package/src/SimulateItems.res.mjs +7 -11
- package/src/TestIndexer.res +1 -1
- package/src/TestIndexer.res.mjs +1 -1
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +19 -12
- package/src/sources/EventRouter.res.mjs +7 -5
- package/src/sources/Evm.res +58 -5
- package/src/sources/Evm.res.mjs +44 -5
- package/src/sources/EvmChain.res +14 -18
- package/src/sources/EvmChain.res.mjs +12 -13
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +8 -3
- package/src/sources/Fuel.res.mjs +5 -4
- package/src/sources/HyperFuelSource.res +31 -40
- package/src/sources/HyperFuelSource.res.mjs +52 -44
- package/src/sources/HyperSync.res +31 -9
- package/src/sources/HyperSync.res.mjs +47 -31
- package/src/sources/HyperSync.resi +10 -3
- package/src/sources/HyperSyncClient.res +15 -4
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +58 -90
- package/src/sources/HyperSyncSource.res.mjs +57 -66
- package/src/sources/RpcSource.res +118 -120
- package/src/sources/RpcSource.res.mjs +92 -74
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +5 -3
- package/src/sources/SimulateSource.res.mjs +12 -4
- package/src/sources/Source.res +19 -5
- package/src/sources/SourceManager.res +60 -10
- package/src/sources/SourceManager.res.mjs +54 -8
- package/src/sources/SourceManager.resi +10 -0
- package/src/sources/Svm.res +14 -10
- package/src/sources/Svm.res.mjs +23 -6
- package/src/sources/SvmHyperSyncClient.res +5 -6
- package/src/sources/SvmHyperSyncSource.res +82 -41
- package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
- package/src/sources/TransactionStore.res +6 -107
- package/src/sources/TransactionStore.res.mjs +5 -86
- package/svm.schema.json +19 -0
|
@@ -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
|
|
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
|
|
57
|
-
|
|
58
|
-
let preRegistered = registry.preRegistered;
|
|
39
|
+
let preRegistered = EnvioGlobal.value.preRegistered;
|
|
59
40
|
|
|
60
41
|
function withRegistration(fn) {
|
|
61
|
-
let r = activeRegistration
|
|
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(
|
|
55
|
+
function startRegistration(config) {
|
|
75
56
|
let r = {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
onBlockByChainId: {}
|
|
79
|
-
},
|
|
57
|
+
config: config,
|
|
58
|
+
registrationsByChainId: {},
|
|
80
59
|
finished: false
|
|
81
60
|
};
|
|
82
|
-
activeRegistration
|
|
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
|
|
92
|
-
let
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return
|
|
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
|
|
111
|
-
let match =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
|
122
|
-
|
|
123
|
-
|
|
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
|
|
175
|
-
|
|
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(
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
/*
|
|
446
|
+
/* blockRangeSchema Not a pure module */
|
package/src/HandlerRegister.resi
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
type
|
|
1
|
+
type chainRegistrations = {
|
|
2
|
+
onEventRegistrations: array<Internal.onEventRegistration>,
|
|
3
|
+
onBlockRegistrations: array<Internal.onBlockRegistration>,
|
|
4
|
+
}
|
|
5
|
+
type registrationsByChainId = dict<chainRegistrations>
|
|
2
6
|
|
|
3
|
-
let startRegistration: (~
|
|
7
|
+
let startRegistration: (~config: Config.t) => unit
|
|
4
8
|
let isPendingRegistration: unit => bool
|
|
5
|
-
let finishRegistration:
|
|
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
|
-
~
|
|
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
|
package/src/IndexerState.res
CHANGED
|
@@ -188,7 +188,7 @@ let makeFromDbState = (
|
|
|
188
188
|
~config: Config.t,
|
|
189
189
|
~persistence: Persistence.t,
|
|
190
190
|
~initialState: Persistence.initialState,
|
|
191
|
-
~
|
|
191
|
+
~registrationsByChainId,
|
|
192
192
|
~isDevelopmentMode=false,
|
|
193
193
|
~shouldUseTui=false,
|
|
194
194
|
~exitAfterFirstEventBlock=false,
|
|
@@ -234,7 +234,7 @@ let makeFromDbState = (
|
|
|
234
234
|
~isInReorgThreshold,
|
|
235
235
|
~isRealtime,
|
|
236
236
|
~config,
|
|
237
|
-
~
|
|
237
|
+
~registrationsByChainId,
|
|
238
238
|
~reducedPollingInterval?,
|
|
239
239
|
),
|
|
240
240
|
)
|
|
@@ -362,7 +362,10 @@ let clearRollback = (state: t) => state.rollbackState = NoRollback
|
|
|
362
362
|
let invalidateInflight = (state: t) => state.epoch = state.epoch + 1
|
|
363
363
|
|
|
364
364
|
let applyBatchProgress = (state: t, ~batch: Batch.t) =>
|
|
365
|
-
state.crossChainState->CrossChainState.applyBatchProgress(
|
|
365
|
+
state.crossChainState->CrossChainState.applyBatchProgress(
|
|
366
|
+
~batch,
|
|
367
|
+
~blockTimestampName=state.config.ecosystem.blockTimestampName,
|
|
368
|
+
)
|
|
366
369
|
|
|
367
370
|
// Processing-loop mutex. Guards ProcessEventBatch re-entry so only one
|
|
368
371
|
// processing loop runs at a time.
|
package/src/IndexerState.res.mjs
CHANGED
|
@@ -97,7 +97,7 @@ function make$2(config, persistence, chainStates, isInReorgThreshold, isRealtime
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
function makeFromDbState(config, persistence, initialState,
|
|
100
|
+
function makeFromDbState(config, persistence, initialState, registrationsByChainId, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, reducedPollingInterval, targetBufferSizeOpt, onError) {
|
|
101
101
|
let isDevelopmentMode = isDevelopmentModeOpt !== undefined ? isDevelopmentModeOpt : false;
|
|
102
102
|
let shouldUseTui = shouldUseTuiOpt !== undefined ? shouldUseTuiOpt : false;
|
|
103
103
|
let exitAfterFirstEventBlock = exitAfterFirstEventBlockOpt !== undefined ? exitAfterFirstEventBlockOpt : false;
|
|
@@ -123,7 +123,7 @@ function makeFromDbState(config, persistence, initialState, registrations, isDev
|
|
|
123
123
|
initialState.chains.forEach(resumedChainState => {
|
|
124
124
|
let chain = Config.getChain(config, resumedChainState.id);
|
|
125
125
|
let chainConfig = ChainMap.get(config.chainMap, chain);
|
|
126
|
-
chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config,
|
|
126
|
+
chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval);
|
|
127
127
|
});
|
|
128
128
|
let allChainsReady = {
|
|
129
129
|
contents: initialState.chains.length !== 0
|
|
@@ -231,7 +231,7 @@ function invalidateInflight(state) {
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
function applyBatchProgress(state, batch) {
|
|
234
|
-
CrossChainState.applyBatchProgress(state.crossChainState, batch);
|
|
234
|
+
CrossChainState.applyBatchProgress(state.crossChainState, batch, state.config.ecosystem.blockTimestampName);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
function isProcessing(state) {
|
package/src/IndexerState.resi
CHANGED
|
@@ -44,7 +44,7 @@ let makeFromDbState: (
|
|
|
44
44
|
~config: Config.t,
|
|
45
45
|
~persistence: Persistence.t,
|
|
46
46
|
~initialState: Persistence.initialState,
|
|
47
|
-
~
|
|
47
|
+
~registrationsByChainId: HandlerRegister.registrationsByChainId,
|
|
48
48
|
~isDevelopmentMode: bool=?,
|
|
49
49
|
~shouldUseTui: bool=?,
|
|
50
50
|
~exitAfterFirstEventBlock: bool=?,
|
|
@@ -8,15 +8,18 @@ let deriveEffectiveStartBlock = (~registrationBlock: int, ~contractStartBlock: o
|
|
|
8
8
|
Pervasives.max(Pervasives.max(registrationBlock, 0), contractStartBlock->Option.getOr(0))
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
let makeContractConfigs = (~
|
|
11
|
+
let makeContractConfigs = (~onEventRegistrations: array<Internal.onEventRegistration>): dict<
|
|
12
|
+
contractConfig,
|
|
13
|
+
> => {
|
|
12
14
|
let contractConfigs: dict<contractConfig> = Dict.make()
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
onEventRegistrations->Array.forEach(reg => {
|
|
16
|
+
let contractName = reg.eventConfig.contractName
|
|
17
|
+
switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
15
18
|
| Some({startBlock}) =>
|
|
16
19
|
contractConfigs->Dict.set(
|
|
17
|
-
|
|
20
|
+
contractName,
|
|
18
21
|
{
|
|
19
|
-
startBlock: switch (startBlock,
|
|
22
|
+
startBlock: switch (startBlock, reg.startBlock) {
|
|
20
23
|
| (Some(a), Some(b)) => Some(Pervasives.min(a, b))
|
|
21
24
|
| (Some(_) as s, None) | (None, Some(_) as s) => s
|
|
22
25
|
| (None, None) => None
|
|
@@ -25,9 +28,9 @@ let makeContractConfigs = (~eventConfigs: array<Internal.eventConfig>): dict<con
|
|
|
25
28
|
)
|
|
26
29
|
| None =>
|
|
27
30
|
contractConfigs->Dict.set(
|
|
28
|
-
|
|
31
|
+
contractName,
|
|
29
32
|
{
|
|
30
|
-
startBlock:
|
|
33
|
+
startBlock: reg.startBlock,
|
|
31
34
|
},
|
|
32
35
|
)
|
|
33
36
|
}
|