envio 3.3.0-alpha.0 → 3.3.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/evm.schema.json +10 -0
- package/index.d.ts +45 -25
- package/package.json +7 -7
- package/src/Address.res +5 -2
- package/src/Address.res.mjs +3 -1
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/Batch.res +0 -6
- package/src/Batch.res.mjs +1 -12
- package/src/BatchProcessing.res +7 -12
- package/src/BatchProcessing.res.mjs +8 -7
- package/src/Bin.res +3 -0
- package/src/Bin.res.mjs +4 -0
- package/src/ChainFetching.res +48 -16
- package/src/ChainFetching.res.mjs +36 -17
- package/src/ChainMetadata.res +1 -11
- package/src/ChainMetadata.res.mjs +1 -10
- package/src/ChainState.res +628 -149
- package/src/ChainState.res.mjs +440 -102
- package/src/ChainState.resi +74 -4
- package/src/Config.res +61 -33
- package/src/Config.res.mjs +50 -10
- package/src/ContractRegisterContext.res +2 -12
- package/src/ContractRegisterContext.res.mjs +3 -5
- package/src/Core.res +14 -3
- package/src/CrossChainState.res +142 -93
- package/src/CrossChainState.res.mjs +88 -60
- package/src/CrossChainState.resi +2 -10
- package/src/Ecosystem.res +5 -6
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Env.res +0 -7
- package/src/Env.res.mjs +0 -6
- package/src/Envio.res +17 -11
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +177 -88
- package/src/EventConfigBuilder.res.mjs +99 -42
- package/src/EventProcessing.res +74 -28
- package/src/EventProcessing.res.mjs +55 -29
- package/src/ExitOnCaughtUp.res +10 -2
- package/src/ExitOnCaughtUp.res.mjs +10 -1
- package/src/FetchState.res +558 -300
- package/src/FetchState.res.mjs +437 -423
- package/src/HandlerLoader.res +8 -104
- package/src/HandlerLoader.res.mjs +2 -81
- package/src/HandlerRegister.res +518 -144
- package/src/HandlerRegister.res.mjs +285 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerLoop.res +2 -3
- package/src/IndexerLoop.res.mjs +1 -1
- package/src/IndexerState.res +10 -11
- package/src/IndexerState.res.mjs +14 -11
- package/src/IndexerState.resi +2 -5
- package/src/IndexingAddresses.res +108 -0
- package/src/IndexingAddresses.res.mjs +101 -0
- package/src/IndexingAddresses.resi +34 -0
- package/src/Internal.res +155 -46
- package/src/Internal.res.mjs +30 -2
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/LogSelection.res +102 -165
- package/src/LogSelection.res.mjs +101 -116
- package/src/Main.res +71 -236
- package/src/Main.res.mjs +60 -145
- package/src/Metrics.res +74 -0
- package/src/Metrics.res.mjs +75 -0
- package/src/PgStorage.res +4 -4
- package/src/PgStorage.res.mjs +5 -5
- package/src/Prometheus.res +10 -74
- package/src/Prometheus.res.mjs +124 -186
- package/src/PruneStaleHistory.res +2 -2
- package/src/PruneStaleHistory.res.mjs +3 -3
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/Rollback.res +3 -3
- package/src/Rollback.res.mjs +4 -4
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateDeadInputTracker.res +85 -0
- package/src/SimulateDeadInputTracker.res.mjs +73 -0
- package/src/SimulateDeadInputTracker.resi +12 -0
- package/src/SimulateItems.res +91 -23
- package/src/SimulateItems.res.mjs +55 -32
- package/src/TestIndexer.res +54 -40
- package/src/TestIndexer.res.mjs +37 -30
- package/src/bindings/Performance.res +7 -0
- package/src/bindings/Performance.res.mjs +21 -0
- package/src/bindings/Performance.resi +7 -0
- package/src/bindings/Viem.res +0 -41
- package/src/bindings/Viem.res.mjs +1 -43
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +36 -33
- package/src/sources/EventRouter.res.mjs +13 -14
- package/src/sources/Evm.res +83 -72
- package/src/sources/Evm.res.mjs +53 -69
- package/src/sources/EvmChain.res +18 -20
- package/src/sources/EvmChain.res.mjs +15 -15
- package/src/sources/EvmRpcClient.res +74 -5
- package/src/sources/EvmRpcClient.res.mjs +13 -4
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +9 -6
- package/src/sources/Fuel.res.mjs +5 -10
- package/src/sources/HyperFuelSource.res +46 -50
- package/src/sources/HyperFuelSource.res.mjs +64 -54
- package/src/sources/HyperSync.res +39 -7
- package/src/sources/HyperSync.res.mjs +57 -37
- package/src/sources/HyperSync.resi +12 -2
- package/src/sources/HyperSyncClient.res +22 -111
- package/src/sources/HyperSyncClient.res.mjs +2 -30
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +94 -107
- package/src/sources/HyperSyncSource.res.mjs +82 -86
- package/src/sources/Rpc.res +15 -47
- package/src/sources/Rpc.res.mjs +25 -56
- package/src/sources/RpcSource.res +320 -467
- package/src/sources/RpcSource.res.mjs +268 -385
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +10 -4
- package/src/sources/SimulateSource.res.mjs +16 -6
- package/src/sources/Source.res +34 -6
- package/src/sources/SourceManager.res +86 -27
- package/src/sources/SourceManager.res.mjs +84 -47
- package/src/sources/SourceManager.resi +12 -3
- package/src/sources/Svm.res +31 -16
- package/src/sources/Svm.res.mjs +36 -13
- package/src/sources/SvmHyperSyncClient.res +5 -32
- package/src/sources/SvmHyperSyncSource.res +159 -134
- package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
- package/src/sources/TransactionStore.res +49 -0
- package/src/sources/TransactionStore.res.mjs +30 -0
- package/src/tui/Tui.res +13 -16
- package/src/tui/Tui.res.mjs +12 -14
- package/svm.schema.json +49 -37
- package/src/bindings/Hrtime.res +0 -58
- package/src/bindings/Hrtime.res.mjs +0 -90
- 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
|
|
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/IndexerLoop.res
CHANGED
|
@@ -19,12 +19,11 @@ let start = (state: IndexerState.t) => {
|
|
|
19
19
|
launch(state, () =>
|
|
20
20
|
state
|
|
21
21
|
->IndexerState.crossChainState
|
|
22
|
-
->CrossChainState.checkAndFetch(~
|
|
22
|
+
->CrossChainState.checkAndFetch(~dispatchChain=(~chain, ~action) =>
|
|
23
23
|
ChainFetching.fetchChain(
|
|
24
24
|
state,
|
|
25
25
|
chain,
|
|
26
|
-
~
|
|
27
|
-
~bufferLimit,
|
|
26
|
+
~action,
|
|
28
27
|
~stateId=state->IndexerState.epoch,
|
|
29
28
|
~scheduleFetch,
|
|
30
29
|
~scheduleProcessing,
|
package/src/IndexerLoop.res.mjs
CHANGED
|
@@ -15,7 +15,7 @@ function launch(state, work) {
|
|
|
15
15
|
|
|
16
16
|
function start(state) {
|
|
17
17
|
let scheduleFetch = () => {
|
|
18
|
-
let work = () => CrossChainState.checkAndFetch(IndexerState.crossChainState(state), (chain,
|
|
18
|
+
let work = () => CrossChainState.checkAndFetch(IndexerState.crossChainState(state), (chain, action) => ChainFetching.fetchChain(state, chain, action, IndexerState.epoch(state), scheduleFetch, scheduleProcessing, scheduleRollback));
|
|
19
19
|
if (!IndexerState.isStopped(state)) {
|
|
20
20
|
work();
|
|
21
21
|
return;
|
package/src/IndexerState.res
CHANGED
|
@@ -108,6 +108,8 @@ type t = {
|
|
|
108
108
|
// waitForNewBlock waiter is bound to the old, pre-realtime source). A fetch
|
|
109
109
|
// response or waiter carrying an older epoch than this is discarded.
|
|
110
110
|
mutable epoch: int,
|
|
111
|
+
// None off the simulate path.
|
|
112
|
+
simulateDeadInputTracker: option<SimulateDeadInputTracker.t>,
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
let make = (
|
|
@@ -116,8 +118,6 @@ let make = (
|
|
|
116
118
|
~chainStates: dict<ChainState.t>,
|
|
117
119
|
~isInReorgThreshold: bool,
|
|
118
120
|
~isRealtime: bool,
|
|
119
|
-
~maxBackfillConcurrency=Env.maxBackfillConcurrency,
|
|
120
|
-
~maxRealtimeConcurrency=Env.maxRealtimeConcurrency,
|
|
121
121
|
~targetBufferSize=CrossChainState.calculateTargetBufferSize(),
|
|
122
122
|
~committedCheckpointId=Internal.initialCheckpointId,
|
|
123
123
|
~isDevelopmentMode=false,
|
|
@@ -160,8 +160,6 @@ let make = (
|
|
|
160
160
|
~chainStates,
|
|
161
161
|
~isInReorgThreshold,
|
|
162
162
|
~isRealtime,
|
|
163
|
-
~maxBackfillConcurrency,
|
|
164
|
-
~maxRealtimeConcurrency,
|
|
165
163
|
~targetBufferSize,
|
|
166
164
|
),
|
|
167
165
|
indexerStartTime: Date.make(),
|
|
@@ -173,6 +171,7 @@ let make = (
|
|
|
173
171
|
onError,
|
|
174
172
|
isStopped: false,
|
|
175
173
|
epoch: 0,
|
|
174
|
+
simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config),
|
|
176
175
|
}
|
|
177
176
|
}
|
|
178
177
|
|
|
@@ -189,13 +188,11 @@ let makeFromDbState = (
|
|
|
189
188
|
~config: Config.t,
|
|
190
189
|
~persistence: Persistence.t,
|
|
191
190
|
~initialState: Persistence.initialState,
|
|
192
|
-
~
|
|
191
|
+
~registrationsByChainId,
|
|
193
192
|
~isDevelopmentMode=false,
|
|
194
193
|
~shouldUseTui=false,
|
|
195
194
|
~exitAfterFirstEventBlock=false,
|
|
196
195
|
~reducedPollingInterval=?,
|
|
197
|
-
~maxBackfillConcurrency=Env.maxBackfillConcurrency,
|
|
198
|
-
~maxRealtimeConcurrency=Env.maxRealtimeConcurrency,
|
|
199
196
|
~targetBufferSize=CrossChainState.calculateTargetBufferSize(),
|
|
200
197
|
~onError,
|
|
201
198
|
) => {
|
|
@@ -237,7 +234,7 @@ let makeFromDbState = (
|
|
|
237
234
|
~isInReorgThreshold,
|
|
238
235
|
~isRealtime,
|
|
239
236
|
~config,
|
|
240
|
-
~
|
|
237
|
+
~registrationsByChainId,
|
|
241
238
|
~reducedPollingInterval?,
|
|
242
239
|
),
|
|
243
240
|
)
|
|
@@ -269,8 +266,6 @@ let makeFromDbState = (
|
|
|
269
266
|
~chainStates,
|
|
270
267
|
~isInReorgThreshold,
|
|
271
268
|
~isRealtime,
|
|
272
|
-
~maxBackfillConcurrency,
|
|
273
|
-
~maxRealtimeConcurrency,
|
|
274
269
|
~targetBufferSize,
|
|
275
270
|
~committedCheckpointId=initialState.checkpointId,
|
|
276
271
|
~isDevelopmentMode,
|
|
@@ -367,7 +362,10 @@ let clearRollback = (state: t) => state.rollbackState = NoRollback
|
|
|
367
362
|
let invalidateInflight = (state: t) => state.epoch = state.epoch + 1
|
|
368
363
|
|
|
369
364
|
let applyBatchProgress = (state: t, ~batch: Batch.t) =>
|
|
370
|
-
state.crossChainState->CrossChainState.applyBatchProgress(
|
|
365
|
+
state.crossChainState->CrossChainState.applyBatchProgress(
|
|
366
|
+
~batch,
|
|
367
|
+
~blockTimestampName=state.config.ecosystem.blockTimestampName,
|
|
368
|
+
)
|
|
371
369
|
|
|
372
370
|
// Processing-loop mutex. Guards ProcessEventBatch re-entry so only one
|
|
373
371
|
// processing loop runs at a time.
|
|
@@ -408,6 +406,7 @@ let exitAfterFirstEventBlock = (state: t) => state.exitAfterFirstEventBlock
|
|
|
408
406
|
let isStopped = (state: t) => state.isStopped
|
|
409
407
|
let epoch = (state: t) => state.epoch
|
|
410
408
|
let pruneStaleEntityHistoryThrottler = (state: t) => state.writeThrottlers.pruneStaleEntityHistory
|
|
409
|
+
let simulateDeadInputTracker = (state: t) => state.simulateDeadInputTracker
|
|
411
410
|
|
|
412
411
|
// --- Store domain operations. ---
|
|
413
412
|
|