envio 3.3.1 → 3.4.0
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/package.json +6 -6
- package/src/Api.res +1 -8
- package/src/Api.res.mjs +1 -5
- package/src/ChainState.res +6 -1
- package/src/ChainState.res.mjs +4 -3
- package/src/Config.res +33 -4
- package/src/Config.res.mjs +34 -5
- package/src/Core.res +30 -19
- package/src/Core.res.mjs +5 -5
- package/src/EnvioGlobal.res +0 -2
- package/src/EnvioGlobal.res.mjs +0 -1
- package/src/ExitOnCaughtUp.res +6 -2
- package/src/ExitOnCaughtUp.res.mjs +4 -0
- package/src/FetchState.res +3 -3
- package/src/HandlerRegister.res +357 -434
- package/src/HandlerRegister.res.mjs +202 -242
- package/src/HandlerRegister.resi +7 -15
- package/src/IndexerState.res +10 -0
- package/src/IndexerState.res.mjs +9 -3
- package/src/IndexerState.resi +3 -0
- package/src/Internal.res +10 -1
- package/src/Main.res.mjs +4 -4
- package/src/PgStorage.res +52 -26
- package/src/PgStorage.res.mjs +32 -23
- package/src/SimulateItems.res +61 -40
- package/src/SimulateItems.res.mjs +37 -21
- package/src/TestIndexer.res +446 -453
- package/src/TestIndexer.res.mjs +320 -343
- package/src/bindings/ClickHouse.res +68 -2
- package/src/bindings/ClickHouse.res.mjs +47 -2
- package/src/sources/EvmChain.res +1 -1
- package/src/sources/EvmChain.res.mjs +2 -2
- package/src/sources/FuelHyperSync.res +74 -0
- package/src/sources/FuelHyperSync.res.mjs +80 -0
- package/src/sources/FuelHyperSync.resi +22 -0
- package/src/sources/FuelHyperSyncClient.res +120 -0
- package/src/sources/FuelHyperSyncClient.res.mjs +71 -0
- package/src/sources/FuelHyperSyncSource.res +257 -0
- package/src/sources/FuelHyperSyncSource.res.mjs +252 -0
- package/src/sources/HyperSyncClient.res +2 -2
- package/src/sources/HyperSyncClient.res.mjs +1 -1
- package/src/sources/SvmHyperSyncClient.res +139 -102
- package/src/sources/SvmHyperSyncClient.res.mjs +45 -5
- package/src/sources/SvmHyperSyncSource.res +60 -440
- package/src/sources/SvmHyperSyncSource.res.mjs +42 -363
- package/src/TestIndexerProxyStorage.res +0 -196
- package/src/TestIndexerProxyStorage.res.mjs +0 -121
- package/src/TestIndexerWorker.res +0 -4
- package/src/TestIndexerWorker.res.mjs +0 -7
- package/src/sources/EventRouter.res +0 -165
- package/src/sources/EventRouter.res.mjs +0 -153
- package/src/sources/HyperFuel.res +0 -179
- package/src/sources/HyperFuel.res.mjs +0 -146
- package/src/sources/HyperFuel.resi +0 -36
- package/src/sources/HyperFuelClient.res +0 -127
- package/src/sources/HyperFuelClient.res.mjs +0 -20
- package/src/sources/HyperFuelSource.res +0 -502
- package/src/sources/HyperFuelSource.res.mjs +0 -481
- /package/src/sources/{HyperSyncSource.res → EvmHyperSyncSource.res} +0 -0
- /package/src/sources/{HyperSyncSource.res.mjs → EvmHyperSyncSource.res.mjs} +0 -0
|
@@ -4,7 +4,6 @@ import * as Utils from "./Utils.res.mjs";
|
|
|
4
4
|
import * as Logging from "./Logging.res.mjs";
|
|
5
5
|
import * as ChainMap from "./ChainMap.res.mjs";
|
|
6
6
|
import * as EnvioGlobal from "./EnvioGlobal.res.mjs";
|
|
7
|
-
import * as EventRouter from "./sources/EventRouter.res.mjs";
|
|
8
7
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
9
8
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
10
9
|
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
@@ -13,27 +12,12 @@ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
|
13
12
|
import * as EventConfigBuilder from "./EventConfigBuilder.res.mjs";
|
|
14
13
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
15
14
|
|
|
16
|
-
let eventRegistrations = EnvioGlobal.value.eventRegistrations;
|
|
17
|
-
|
|
18
15
|
function getKey(contractName, eventName) {
|
|
19
16
|
return contractName + "." + eventName;
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
if (existing !== undefined) {
|
|
25
|
-
return existing;
|
|
26
|
-
} else {
|
|
27
|
-
return {
|
|
28
|
-
handler: undefined,
|
|
29
|
-
contractRegister: undefined,
|
|
30
|
-
eventOptions: undefined
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function set(contractName, eventName, registration) {
|
|
36
|
-
eventRegistrations[getKey(contractName, eventName)] = registration;
|
|
19
|
+
function resetOnEventRegistrations() {
|
|
20
|
+
EnvioGlobal.value.activeRegistration = undefined;
|
|
37
21
|
}
|
|
38
22
|
|
|
39
23
|
let preRegistered = EnvioGlobal.value.preRegistered;
|
|
@@ -53,27 +37,28 @@ function withRegistration(fn) {
|
|
|
53
37
|
}
|
|
54
38
|
|
|
55
39
|
function startRegistration(config) {
|
|
40
|
+
let match = EnvioGlobal.value.activeRegistration;
|
|
41
|
+
if (match !== undefined) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
56
44
|
let r = {
|
|
57
45
|
config: config,
|
|
58
46
|
registrationsByChainId: {},
|
|
59
47
|
finished: false
|
|
60
48
|
};
|
|
61
49
|
EnvioGlobal.value.activeRegistration = Primitive_option.some(r);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
fn(r);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
50
|
+
let queued = preRegistered.slice();
|
|
51
|
+
preRegistered.splice(0, preRegistered.length);
|
|
52
|
+
queued.forEach(fn => fn(r));
|
|
68
53
|
}
|
|
69
54
|
|
|
70
|
-
function
|
|
55
|
+
function getChainRegistrations(r, chainId) {
|
|
71
56
|
let key = chainId.toString();
|
|
72
|
-
let
|
|
73
|
-
if (
|
|
74
|
-
return
|
|
57
|
+
let existing = r.registrationsByChainId[key];
|
|
58
|
+
if (existing !== undefined) {
|
|
59
|
+
return existing;
|
|
75
60
|
}
|
|
76
|
-
let fresh_onEventRegistrations =
|
|
61
|
+
let fresh_onEventRegistrations = [];
|
|
77
62
|
let fresh_onBlockRegistrations = [];
|
|
78
63
|
let fresh = {
|
|
79
64
|
onEventRegistrations: fresh_onEventRegistrations,
|
|
@@ -95,164 +80,221 @@ function buildOnEventRegistrationWith(config, chainId, eventConfig, isWildcard,
|
|
|
95
80
|
}
|
|
96
81
|
}
|
|
97
82
|
|
|
98
|
-
function
|
|
99
|
-
|
|
100
|
-
|
|
83
|
+
function sameEventAndFilter(a, b, config) {
|
|
84
|
+
if (a.eventConfig.contractName !== b.eventConfig.contractName || a.eventConfig.name !== b.eventConfig.name || a.isWildcard !== b.isWildcard) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
let match = config.ecosystem.name;
|
|
88
|
+
switch (match) {
|
|
89
|
+
case "evm" :
|
|
90
|
+
return Primitive_object.equal(a.resolvedWhere, b.resolvedWhere);
|
|
91
|
+
case "fuel" :
|
|
92
|
+
case "svm" :
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
101
95
|
}
|
|
102
96
|
|
|
103
|
-
function
|
|
104
|
-
|
|
97
|
+
function mergeRegistrations(resolved, config) {
|
|
98
|
+
let merged = {
|
|
99
|
+
contents: []
|
|
100
|
+
};
|
|
101
|
+
resolved.forEach(reg => {
|
|
102
|
+
if (Stdlib_Option.isSome(reg.handler)) {
|
|
103
|
+
let i = merged.contents.findIndex(m => {
|
|
104
|
+
if (Stdlib_Option.isNone(m.handler) && Stdlib_Option.isSome(m.contractRegister)) {
|
|
105
|
+
return sameEventAndFilter(m, reg, config);
|
|
106
|
+
} else {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
if (i === -1) {
|
|
111
|
+
merged.contents = merged.contents.concat([reg]);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
let target = merged.contents[i];
|
|
115
|
+
let newrecord = {...reg};
|
|
116
|
+
merged.contents = merged.contents.filter((param, j) => j !== i).concat([(newrecord.contractRegister = target.contractRegister, newrecord)]);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
let i$1 = merged.contents.findIndex(m => {
|
|
120
|
+
if (Stdlib_Option.isSome(m.handler) && Stdlib_Option.isNone(m.contractRegister)) {
|
|
121
|
+
return sameEventAndFilter(m, reg, config);
|
|
122
|
+
} else {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
if (i$1 === -1) {
|
|
127
|
+
merged.contents = merged.contents.concat([reg]);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let target$1 = merged.contents[i$1];
|
|
131
|
+
let next = merged.contents.slice();
|
|
132
|
+
let newrecord$1 = {...target$1};
|
|
133
|
+
newrecord$1.contractRegister = reg.contractRegister;
|
|
134
|
+
next[i$1] = newrecord$1;
|
|
135
|
+
merged.contents = next;
|
|
136
|
+
});
|
|
137
|
+
return merged.contents;
|
|
105
138
|
}
|
|
106
139
|
|
|
107
|
-
function
|
|
108
|
-
|
|
140
|
+
function isDroppedByWhere(config, reg) {
|
|
141
|
+
if (config.ecosystem.name === "evm") {
|
|
142
|
+
return Utils.$$Array.isEmpty(reg.resolvedWhere.topicSelections);
|
|
143
|
+
} else {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
109
146
|
}
|
|
110
147
|
|
|
111
|
-
function
|
|
112
|
-
|
|
148
|
+
function addOnEventRegistration(registration, contractName, eventName, handler, contractRegister, eventOptions) {
|
|
149
|
+
let isWildcard = Stdlib_Option.getOr(Stdlib_Option.flatMap(eventOptions, v => v.wildcard), false);
|
|
150
|
+
let where = Stdlib_Option.flatMap(eventOptions, v => v.where);
|
|
151
|
+
ChainMap.values(registration.config.chainMap).forEach(chainConfig => {
|
|
152
|
+
let contract = chainConfig.contracts.find(c => c.name === contractName);
|
|
153
|
+
if (contract === undefined) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
let eventConfig = contract.events.find(e => e.name === eventName);
|
|
157
|
+
if (eventConfig === undefined) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
let reg = buildOnEventRegistrationWith(registration.config, chainConfig.id, eventConfig, isWildcard, handler, contractRegister, where, contract.startBlock);
|
|
161
|
+
getChainRegistrations(registration, chainConfig.id).onEventRegistrations.push(reg);
|
|
162
|
+
});
|
|
113
163
|
}
|
|
114
164
|
|
|
115
|
-
function
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
165
|
+
function setHandler(contractName, eventName, handler, eventOptions) {
|
|
166
|
+
withRegistration(registration => {
|
|
167
|
+
let eventOptions$1 = Stdlib_Option.map(eventOptions, v => v);
|
|
168
|
+
addOnEventRegistration(registration, contractName, eventName, handler, undefined, eventOptions$1);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function setContractRegister(contractName, eventName, contractRegister, eventOptions) {
|
|
173
|
+
withRegistration(registration => {
|
|
174
|
+
let eventOptions$1 = Stdlib_Option.map(eventOptions, v => v);
|
|
175
|
+
addOnEventRegistration(registration, contractName, eventName, undefined, contractRegister, eventOptions$1);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function storedOnEventRegistrations(r, chainId) {
|
|
180
|
+
let chainRegs = r.registrationsByChainId[chainId.toString()];
|
|
181
|
+
if (chainRegs !== undefined) {
|
|
182
|
+
return chainRegs.onEventRegistrations;
|
|
119
183
|
} else {
|
|
120
|
-
return
|
|
184
|
+
return [];
|
|
121
185
|
}
|
|
122
186
|
}
|
|
123
187
|
|
|
124
|
-
function
|
|
125
|
-
let
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
188
|
+
function isWildcard(contractName, eventName) {
|
|
189
|
+
let r = EnvioGlobal.value.activeRegistration;
|
|
190
|
+
if (r !== undefined) {
|
|
191
|
+
return Object.values(r.registrationsByChainId).some(chainRegs => chainRegs.onEventRegistrations.some(reg => {
|
|
192
|
+
if (reg.eventConfig.contractName === contractName && reg.eventConfig.name === eventName) {
|
|
193
|
+
return reg.isWildcard;
|
|
194
|
+
} else {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}));
|
|
198
|
+
} else {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
131
201
|
}
|
|
132
202
|
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
203
|
+
function getSimulateOnEventRegistrations(config, chainId, eventConfig) {
|
|
204
|
+
let r = EnvioGlobal.value.activeRegistration;
|
|
205
|
+
let stored = r !== undefined ? storedOnEventRegistrations(r, chainId) : [];
|
|
206
|
+
let matching = mergeRegistrations(stored, config).filter(reg => {
|
|
207
|
+
if (reg.eventConfig.contractName === eventConfig.contractName) {
|
|
208
|
+
return reg.eventConfig.name === eventConfig.name;
|
|
137
209
|
} else {
|
|
138
210
|
return false;
|
|
139
211
|
}
|
|
212
|
+
});
|
|
213
|
+
if (Utils.$$Array.notEmpty(matching)) {
|
|
214
|
+
return matching;
|
|
140
215
|
} else {
|
|
141
|
-
return
|
|
216
|
+
return [buildOnEventRegistrationWith(config, chainId, eventConfig, false, undefined, undefined, undefined, undefined)];
|
|
142
217
|
}
|
|
143
218
|
}
|
|
144
219
|
|
|
145
|
-
function
|
|
146
|
-
let
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
220
|
+
function finishRegistration(config) {
|
|
221
|
+
let r = EnvioGlobal.value.activeRegistration;
|
|
222
|
+
if (r === undefined) {
|
|
223
|
+
return Stdlib_JsError.throwWithMessage("The indexer has not started registering handlers, so can't finish it.");
|
|
224
|
+
}
|
|
225
|
+
r.finished = true;
|
|
226
|
+
let notRegisteredEventsByContract = {};
|
|
227
|
+
let registrationsByChainId = {};
|
|
150
228
|
ChainMap.values(config.chainMap).forEach(chainConfig => {
|
|
229
|
+
let chainId = chainConfig.id;
|
|
230
|
+
let key = chainId.toString();
|
|
231
|
+
let builtRegs = mergeRegistrations(storedOnEventRegistrations(r, chainId), config);
|
|
232
|
+
let registeredKeys = new Set();
|
|
233
|
+
builtRegs.forEach(reg => {
|
|
234
|
+
registeredKeys.add(getKey(reg.eventConfig.contractName, reg.eventConfig.name));
|
|
235
|
+
});
|
|
236
|
+
let rawEventRegs = [];
|
|
151
237
|
chainConfig.contracts.forEach(contract => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
238
|
+
contract.events.forEach(eventConfig => {
|
|
239
|
+
if (registeredKeys.has(getKey(contract.name, eventConfig.name))) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (config.enableRawEvents) {
|
|
243
|
+
rawEventRegs.push(buildOnEventRegistrationWith(config, chainId, eventConfig, false, undefined, undefined, undefined, contract.startBlock));
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
let set = notRegisteredEventsByContract[contract.name];
|
|
247
|
+
let eventNames;
|
|
248
|
+
if (set !== undefined) {
|
|
249
|
+
eventNames = Primitive_option.valFromOption(set);
|
|
250
|
+
} else {
|
|
251
|
+
let set$1 = new Set();
|
|
252
|
+
notRegisteredEventsByContract[contract.name] = set$1;
|
|
253
|
+
eventNames = set$1;
|
|
254
|
+
}
|
|
255
|
+
eventNames.add(eventConfig.name);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
let onEventRegistrations = [];
|
|
259
|
+
builtRegs.concat(rawEventRegs).forEach(reg => {
|
|
260
|
+
if (isDroppedByWhere(config, reg)) {
|
|
157
261
|
return;
|
|
158
262
|
}
|
|
159
|
-
let
|
|
160
|
-
|
|
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;
|
|
263
|
+
let newrecord = {...reg};
|
|
264
|
+
onEventRegistrations.push((newrecord.index = onEventRegistrations.length, newrecord));
|
|
166
265
|
});
|
|
266
|
+
let chainRegs = r.registrationsByChainId[key];
|
|
267
|
+
registrationsByChainId[key] = {
|
|
268
|
+
onEventRegistrations: onEventRegistrations,
|
|
269
|
+
onBlockRegistrations: chainRegs !== undefined ? chainRegs.onBlockRegistrations.slice() : []
|
|
270
|
+
};
|
|
167
271
|
});
|
|
272
|
+
let notRegisteredEntries = Object.entries(notRegisteredEventsByContract);
|
|
273
|
+
if (Utils.$$Array.notEmpty(notRegisteredEntries)) {
|
|
274
|
+
let groups = notRegisteredEntries.map(param => param[0] + ` (` + Array.from(param[1]).join(", ") + `)`).join(", ");
|
|
275
|
+
Logging.childInfo(Logging.getLogger(), `Events without a handler, skipped for indexing: ` + groups);
|
|
276
|
+
}
|
|
277
|
+
return registrationsByChainId;
|
|
168
278
|
}
|
|
169
279
|
|
|
170
|
-
function
|
|
171
|
-
let
|
|
172
|
-
if (
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
let t = get(contractName, eventName);
|
|
176
|
-
let existingValue = t.eventOptions;
|
|
177
|
-
if (existingValue !== undefined) {
|
|
178
|
-
if (!eventOptionsMatch(existingValue, eventOptions)) {
|
|
179
|
-
return raiseDuplicateRegistration(contractName, eventName, "Cannot register handler with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
|
|
180
|
-
} else {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
280
|
+
function isPendingRegistration() {
|
|
281
|
+
let r = EnvioGlobal.value.activeRegistration;
|
|
282
|
+
if (r !== undefined) {
|
|
283
|
+
return !r.finished;
|
|
183
284
|
} else {
|
|
184
|
-
return
|
|
185
|
-
handler: t.handler,
|
|
186
|
-
contractRegister: t.contractRegister,
|
|
187
|
-
eventOptions: eventOptions
|
|
188
|
-
});
|
|
285
|
+
return false;
|
|
189
286
|
}
|
|
190
287
|
}
|
|
191
288
|
|
|
192
|
-
function
|
|
193
|
-
let
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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);
|
|
211
|
-
}
|
|
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
|
|
219
|
-
});
|
|
220
|
-
}
|
|
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);
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function setContractRegister(contractName, eventName, contractRegister, eventOptions, loggerOpt) {
|
|
226
|
-
let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
|
|
227
|
-
withRegistration(registration => {
|
|
228
|
-
let t = get(contractName, eventName);
|
|
229
|
-
let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
|
|
230
|
-
let prevContractRegister = t.contractRegister;
|
|
231
|
-
if (prevContractRegister !== undefined) {
|
|
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);
|
|
244
|
-
}
|
|
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
|
|
252
|
-
});
|
|
253
|
-
}
|
|
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
|
-
});
|
|
289
|
+
function throwIfFinishedRegistration(methodName) {
|
|
290
|
+
let match = EnvioGlobal.value.activeRegistration;
|
|
291
|
+
if (match === undefined) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
let match$1 = match.finished;
|
|
295
|
+
if (match$1) {
|
|
296
|
+
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.`);
|
|
297
|
+
}
|
|
256
298
|
}
|
|
257
299
|
|
|
258
300
|
let blockRangeSchema = S$RescriptSchema.strict(S$RescriptSchema.object(s => ({
|
|
@@ -330,9 +372,9 @@ function registerOnBlock(name, where, handler, getChainsObject) {
|
|
|
330
372
|
if (chainEndBlock !== undefined && Stdlib_Option.getOr(range._lte, chainEndBlock) > chainEndBlock) {
|
|
331
373
|
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
374
|
}
|
|
333
|
-
let
|
|
334
|
-
|
|
335
|
-
index:
|
|
375
|
+
let chainRegs = getChainRegistrations(registration, chainId);
|
|
376
|
+
chainRegs.onBlockRegistrations.push({
|
|
377
|
+
index: chainRegs.onBlockRegistrations.length,
|
|
336
378
|
name: name,
|
|
337
379
|
chainId: chainId,
|
|
338
380
|
startBlock: range._gte,
|
|
@@ -347,99 +389,17 @@ function registerOnBlock(name, where, handler, getChainsObject) {
|
|
|
347
389
|
});
|
|
348
390
|
}
|
|
349
391
|
|
|
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
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
let newrecord = {...registration$1};
|
|
395
|
-
onEventRegistrations.push((newrecord.index = onEventRegistrations.length, newrecord));
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
registrationsByChainId[key] = {
|
|
399
|
-
onEventRegistrations: onEventRegistrations,
|
|
400
|
-
onBlockRegistrations: pending !== undefined ? pending.onBlockRegistrations : []
|
|
401
|
-
};
|
|
402
|
-
});
|
|
403
|
-
let notRegisteredEntries = Object.entries(notRegisteredEventsByContract);
|
|
404
|
-
if (Utils.$$Array.notEmpty(notRegisteredEntries)) {
|
|
405
|
-
let groups = notRegisteredEntries.map(param => param[0] + ` (` + Array.from(param[1]).join(", ") + `)`).join(", ");
|
|
406
|
-
Logging.childInfo(Logging.getLogger(), `Events without a handler, skipped for indexing: ` + groups);
|
|
407
|
-
}
|
|
408
|
-
return registrationsByChainId;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function isPendingRegistration() {
|
|
412
|
-
let r = EnvioGlobal.value.activeRegistration;
|
|
413
|
-
if (r !== undefined) {
|
|
414
|
-
return !r.finished;
|
|
415
|
-
} else {
|
|
416
|
-
return false;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function throwIfFinishedRegistration(methodName) {
|
|
421
|
-
let match = EnvioGlobal.value.activeRegistration;
|
|
422
|
-
if (match === undefined) {
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
let match$1 = match.finished;
|
|
426
|
-
if (match$1) {
|
|
427
|
-
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.`);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
392
|
export {
|
|
432
393
|
startRegistration,
|
|
394
|
+
resetOnEventRegistrations,
|
|
433
395
|
isPendingRegistration,
|
|
434
396
|
finishRegistration,
|
|
435
397
|
throwIfFinishedRegistration,
|
|
436
|
-
buildOnEventRegistration,
|
|
437
398
|
setHandler,
|
|
438
399
|
setContractRegister,
|
|
439
|
-
getHandler,
|
|
440
|
-
getContractRegister,
|
|
441
400
|
isWildcard,
|
|
442
|
-
|
|
401
|
+
isDroppedByWhere,
|
|
402
|
+
getSimulateOnEventRegistrations,
|
|
443
403
|
blockRangeSchema,
|
|
444
404
|
defaultBlockRange,
|
|
445
405
|
registerOnBlock,
|
package/src/HandlerRegister.resi
CHANGED
|
@@ -5,38 +5,30 @@ type chainRegistrations = {
|
|
|
5
5
|
type registrationsByChainId = dict<chainRegistrations>
|
|
6
6
|
|
|
7
7
|
let startRegistration: (~config: Config.t) => unit
|
|
8
|
+
let resetOnEventRegistrations: unit => unit
|
|
8
9
|
let isPendingRegistration: unit => bool
|
|
9
10
|
let finishRegistration: (~config: Config.t) => registrationsByChainId
|
|
10
11
|
let throwIfFinishedRegistration: (~methodName: string) => unit
|
|
11
12
|
|
|
12
|
-
let buildOnEventRegistration: (
|
|
13
|
-
~config: Config.t,
|
|
14
|
-
~chainId: int,
|
|
15
|
-
~eventConfig: Internal.eventConfig,
|
|
16
|
-
~startBlock: int=?,
|
|
17
|
-
) => Internal.onEventRegistration
|
|
18
|
-
|
|
19
13
|
let setHandler: (
|
|
20
14
|
~contractName: string,
|
|
21
15
|
~eventName: string,
|
|
22
16
|
Internal.genericHandler<Internal.genericHandlerArgs<'event, Internal.handlerContext>>,
|
|
23
17
|
~eventOptions: option<Internal.eventOptions<'where>>,
|
|
24
|
-
~logger: Pino.t=?,
|
|
25
18
|
) => unit
|
|
26
19
|
let setContractRegister: (
|
|
27
20
|
~contractName: string,
|
|
28
21
|
~eventName: string,
|
|
29
22
|
Internal.genericContractRegister<Internal.genericContractRegisterArgs<'event, 'context>>,
|
|
30
23
|
~eventOptions: option<Internal.eventOptions<'where>>,
|
|
31
|
-
~logger: Pino.t=?,
|
|
32
24
|
) => unit
|
|
33
|
-
let getHandler: (~contractName: string, ~eventName: string) => option<Internal.handler>
|
|
34
|
-
let getContractRegister: (
|
|
35
|
-
~contractName: string,
|
|
36
|
-
~eventName: string,
|
|
37
|
-
) => option<Internal.contractRegister>
|
|
38
25
|
let isWildcard: (~contractName: string, ~eventName: string) => bool
|
|
39
|
-
let
|
|
26
|
+
let isDroppedByWhere: (~config: Config.t, Internal.onEventRegistration) => bool
|
|
27
|
+
let getSimulateOnEventRegistrations: (
|
|
28
|
+
~config: Config.t,
|
|
29
|
+
~chainId: int,
|
|
30
|
+
~eventConfig: Internal.eventConfig,
|
|
31
|
+
) => array<Internal.onEventRegistration>
|
|
40
32
|
|
|
41
33
|
type blockRange = {
|
|
42
34
|
_gte: option<int>,
|
package/src/IndexerState.res
CHANGED
|
@@ -115,6 +115,11 @@ type t = {
|
|
|
115
115
|
exitAfterFirstEventBlock: bool,
|
|
116
116
|
// The single fatal-error handler.
|
|
117
117
|
onError: ErrorHandling.t => unit,
|
|
118
|
+
// Invoked once when the indexer catches up and would otherwise exit the
|
|
119
|
+
// process. `None` keeps the production behavior (exit the process); the
|
|
120
|
+
// in-process test runner injects a callback that resolves its run promise
|
|
121
|
+
// instead, so a caught-up run doesn't kill the test process.
|
|
122
|
+
onExit: option<unit => unit>,
|
|
118
123
|
// Set once on any fatal error. Every loop checks it to stop iterating and
|
|
119
124
|
// every launch skips when it's set, so a single failure quiesces the indexer.
|
|
120
125
|
mutable isStopped: bool,
|
|
@@ -149,6 +154,7 @@ let make = (
|
|
|
149
154
|
~shouldUseTui=false,
|
|
150
155
|
~exitAfterFirstEventBlock=false,
|
|
151
156
|
~onError: ErrorHandling.t => unit,
|
|
157
|
+
~onExit=?,
|
|
152
158
|
) => {
|
|
153
159
|
let chainMetaThrottler = {
|
|
154
160
|
let intervalMillis = Env.ThrottleWrites.chainMetadataIntervalMillis
|
|
@@ -194,6 +200,7 @@ let make = (
|
|
|
194
200
|
keepProcessAlive: isDevelopmentMode || shouldUseTui,
|
|
195
201
|
exitAfterFirstEventBlock,
|
|
196
202
|
onError,
|
|
203
|
+
onExit,
|
|
197
204
|
isStopped: false,
|
|
198
205
|
epoch: 0,
|
|
199
206
|
simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config),
|
|
@@ -229,6 +236,7 @@ let makeFromDbState = (
|
|
|
229
236
|
~reducedPollingInterval=?,
|
|
230
237
|
~targetBufferSize=CrossChainState.calculateTargetBufferSize(),
|
|
231
238
|
~onError,
|
|
239
|
+
~onExit=?,
|
|
232
240
|
) => {
|
|
233
241
|
let isInReorgThreshold = if initialState.cleanRun {
|
|
234
242
|
false
|
|
@@ -280,6 +288,7 @@ let makeFromDbState = (
|
|
|
280
288
|
~shouldUseTui,
|
|
281
289
|
~exitAfterFirstEventBlock,
|
|
282
290
|
~onError,
|
|
291
|
+
~onExit?,
|
|
283
292
|
)
|
|
284
293
|
initialState.cache->Utils.Dict.forEach(({effectName, count, scope}) => {
|
|
285
294
|
state.effectState->EffectState.setUnregisteredCacheCount(~effectName, ~scope, ~count)
|
|
@@ -415,6 +424,7 @@ let indexerStartTime = (state: t) => state.indexerStartTime
|
|
|
415
424
|
let loadManager = (state: t) => state.loadManager
|
|
416
425
|
let keepProcessAlive = (state: t) => state.keepProcessAlive
|
|
417
426
|
let exitAfterFirstEventBlock = (state: t) => state.exitAfterFirstEventBlock
|
|
427
|
+
let onExit = (state: t) => state.onExit
|
|
418
428
|
let isStopped = (state: t) => state.isStopped
|
|
419
429
|
let epoch = (state: t) => state.epoch
|
|
420
430
|
let lastPrunedAtMillis = (state: t) => state.lastPrunedAtMillis
|