envio 3.3.0-alpha.2 → 3.3.0-alpha.3
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 -21
- package/package.json +6 -6
- package/src/ChainFetching.res +25 -0
- package/src/ChainFetching.res.mjs +19 -0
- package/src/CrossChainState.res +15 -0
- package/src/CrossChainState.res.mjs +12 -0
- package/src/Ecosystem.res +0 -2
- package/src/EventConfigBuilder.res +42 -18
- package/src/EventConfigBuilder.res.mjs +21 -9
- package/src/EventProcessing.res +53 -37
- package/src/EventProcessing.res.mjs +41 -36
- package/src/FetchState.res +53 -43
- package/src/FetchState.res.mjs +71 -54
- package/src/HandlerLoader.res +10 -1
- package/src/HandlerLoader.res.mjs +15 -8
- package/src/Internal.res +3 -3
- package/src/Internal.res.mjs +1 -1
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/PgStorage.res +4 -4
- package/src/PgStorage.res.mjs +5 -5
- package/src/Prometheus.res +10 -10
- package/src/Prometheus.res.mjs +9 -9
- package/src/PruneStaleHistory.res +2 -2
- package/src/PruneStaleHistory.res.mjs +3 -3
- package/src/Rollback.res +2 -2
- package/src/Rollback.res.mjs +3 -3
- package/src/SimulateItems.res +77 -15
- package/src/SimulateItems.res.mjs +63 -20
- package/src/TestIndexer.res +48 -36
- package/src/TestIndexer.res.mjs +35 -28
- package/src/bindings/Performance.res +7 -0
- package/src/bindings/Performance.res.mjs +21 -0
- package/src/bindings/Performance.resi +7 -0
- package/src/sources/EventRouter.res +17 -21
- package/src/sources/EventRouter.res.mjs +6 -9
- package/src/sources/Evm.res +1 -35
- package/src/sources/Evm.res.mjs +2 -37
- package/src/sources/Fuel.res +0 -2
- package/src/sources/Fuel.res.mjs +0 -6
- package/src/sources/HyperFuelSource.res +10 -11
- package/src/sources/HyperFuelSource.res.mjs +11 -11
- package/src/sources/HyperSync.res +3 -0
- package/src/sources/HyperSync.res.mjs +1 -0
- package/src/sources/HyperSync.resi +1 -0
- package/src/sources/HyperSyncClient.res +5 -1
- package/src/sources/HyperSyncSource.res +42 -24
- package/src/sources/HyperSyncSource.res.mjs +30 -26
- package/src/sources/RpcSource.res +7 -8
- package/src/sources/RpcSource.res.mjs +8 -8
- package/src/sources/SimulateSource.res +1 -1
- package/src/sources/Source.res +1 -1
- package/src/sources/SourceManager.res +17 -16
- package/src/sources/SourceManager.res.mjs +10 -15
- package/src/sources/Svm.res +4 -10
- package/src/sources/Svm.res.mjs +5 -12
- package/src/sources/SvmHyperSyncSource.res +24 -18
- package/src/sources/SvmHyperSyncSource.res.mjs +22 -15
- package/src/sources/TransactionStore.res +59 -42
- package/src/sources/TransactionStore.res.mjs +21 -1
- package/svm.schema.json +30 -37
- package/src/bindings/Hrtime.res +0 -58
- package/src/bindings/Hrtime.res.mjs +0 -90
- package/src/bindings/Hrtime.resi +0 -30
package/src/PgStorage.res.mjs
CHANGED
|
@@ -8,13 +8,13 @@ import * as Table from "./db/Table.res.mjs";
|
|
|
8
8
|
import * as Utils from "./Utils.res.mjs";
|
|
9
9
|
import * as Config from "./Config.res.mjs";
|
|
10
10
|
import * as Hasura from "./Hasura.res.mjs";
|
|
11
|
-
import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
12
11
|
import * as Schema from "./db/Schema.res.mjs";
|
|
13
12
|
import * as Logging from "./Logging.res.mjs";
|
|
14
13
|
import * as Internal from "./Internal.res.mjs";
|
|
15
14
|
import Postgres from "postgres";
|
|
16
15
|
import * as ChainState from "./ChainState.res.mjs";
|
|
17
16
|
import * as Prometheus from "./Prometheus.res.mjs";
|
|
17
|
+
import * as Performance from "./bindings/Performance.res.mjs";
|
|
18
18
|
import * as Persistence from "./Persistence.res.mjs";
|
|
19
19
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
20
20
|
import * as EntityHistory from "./db/EntityHistory.res.mjs";
|
|
@@ -1116,16 +1116,16 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1116
1116
|
}
|
|
1117
1117
|
let sinkPromise;
|
|
1118
1118
|
if (sink !== undefined) {
|
|
1119
|
-
let timerRef =
|
|
1119
|
+
let timerRef = Performance.now();
|
|
1120
1120
|
sinkPromise = sink.writeBatch(batch, chUpdates).then(() => {
|
|
1121
|
-
Prometheus.StorageWrite.increment(sink.name,
|
|
1121
|
+
Prometheus.StorageWrite.increment(sink.name, Performance.secondsSince(timerRef));
|
|
1122
1122
|
}).catch(exn => exn);
|
|
1123
1123
|
} else {
|
|
1124
1124
|
sinkPromise = undefined;
|
|
1125
1125
|
}
|
|
1126
|
-
let primaryTimerRef =
|
|
1126
|
+
let primaryTimerRef = Performance.now();
|
|
1127
1127
|
await writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, updatedEffectsCache, pgUpdates, sinkPromise, chainMetaData, undefined);
|
|
1128
|
-
return Prometheus.StorageWrite.increment("postgres",
|
|
1128
|
+
return Prometheus.StorageWrite.increment("postgres", Performance.secondsSince(primaryTimerRef));
|
|
1129
1129
|
};
|
|
1130
1130
|
let close = () => sql.end();
|
|
1131
1131
|
return {
|
package/src/Prometheus.res
CHANGED
|
@@ -212,7 +212,7 @@ module PreloadHandler = {
|
|
|
212
212
|
|
|
213
213
|
type operationRef = {
|
|
214
214
|
mutable pendingCount: int,
|
|
215
|
-
timerRef:
|
|
215
|
+
timerRef: Performance.timeRef,
|
|
216
216
|
}
|
|
217
217
|
let operations: dict<operationRef> = Dict.make()
|
|
218
218
|
|
|
@@ -227,11 +227,11 @@ module PreloadHandler = {
|
|
|
227
227
|
key,
|
|
228
228
|
{
|
|
229
229
|
pendingCount: 1,
|
|
230
|
-
timerRef:
|
|
230
|
+
timerRef: Performance.now(),
|
|
231
231
|
},
|
|
232
232
|
)
|
|
233
233
|
}
|
|
234
|
-
|
|
234
|
+
Performance.now()
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
let endOperation = (timerRef, ~contract, ~event) => {
|
|
@@ -242,13 +242,13 @@ module PreloadHandler = {
|
|
|
242
242
|
if operationRef.pendingCount === 0 {
|
|
243
243
|
timeCounter->SafeCounter.handleFloat(
|
|
244
244
|
~labels,
|
|
245
|
-
~value=operationRef.timerRef->
|
|
245
|
+
~value=operationRef.timerRef->Performance.secondsSince,
|
|
246
246
|
)
|
|
247
247
|
operations->Utils.Dict.deleteInPlace(key)
|
|
248
248
|
}
|
|
249
249
|
sumTimeCounter->SafeCounter.handleFloat(
|
|
250
250
|
~labels,
|
|
251
|
-
~value=timerRef->
|
|
251
|
+
~value=timerRef->Performance.secondsSince,
|
|
252
252
|
)
|
|
253
253
|
count->SafeCounter.increment(~labels)
|
|
254
254
|
}
|
|
@@ -764,7 +764,7 @@ module StorageLoad = {
|
|
|
764
764
|
|
|
765
765
|
type operationRef = {
|
|
766
766
|
mutable pendingCount: int,
|
|
767
|
-
timerRef:
|
|
767
|
+
timerRef: Performance.timeRef,
|
|
768
768
|
}
|
|
769
769
|
let operations = Dict.make()
|
|
770
770
|
|
|
@@ -780,12 +780,12 @@ module StorageLoad = {
|
|
|
780
780
|
(
|
|
781
781
|
{
|
|
782
782
|
pendingCount: 1,
|
|
783
|
-
timerRef:
|
|
783
|
+
timerRef: Performance.now(),
|
|
784
784
|
}: operationRef
|
|
785
785
|
),
|
|
786
786
|
)
|
|
787
787
|
}
|
|
788
|
-
|
|
788
|
+
Performance.now()
|
|
789
789
|
}
|
|
790
790
|
|
|
791
791
|
let endOperation = (timerRef, ~storage, ~operation, ~whereSize, ~size) => {
|
|
@@ -796,13 +796,13 @@ module StorageLoad = {
|
|
|
796
796
|
if operationRef.pendingCount === 0 {
|
|
797
797
|
timeCounter->SafeCounter.handleFloat(
|
|
798
798
|
~labels,
|
|
799
|
-
~value=operationRef.timerRef->
|
|
799
|
+
~value=operationRef.timerRef->Performance.secondsSince,
|
|
800
800
|
)
|
|
801
801
|
operations->Utils.Dict.deleteInPlace(key)
|
|
802
802
|
}
|
|
803
803
|
sumTimeCounter->SafeCounter.handleFloat(
|
|
804
804
|
~labels,
|
|
805
|
-
~value=timerRef->
|
|
805
|
+
~value=timerRef->Performance.secondsSince,
|
|
806
806
|
)
|
|
807
807
|
counter->SafeCounter.increment(~labels)
|
|
808
808
|
whereSizeCounter->SafeCounter.handleInt(~labels, ~value=whereSize)
|
package/src/Prometheus.res.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Utils from "./Utils.res.mjs";
|
|
4
|
-
import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
5
4
|
import * as PromClient from "./bindings/PromClient.res.mjs";
|
|
5
|
+
import * as Performance from "./bindings/Performance.res.mjs";
|
|
6
6
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
7
7
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
8
8
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
@@ -290,10 +290,10 @@ function startOperation(contract, event) {
|
|
|
290
290
|
} else {
|
|
291
291
|
operations[key] = {
|
|
292
292
|
pendingCount: 1,
|
|
293
|
-
timerRef:
|
|
293
|
+
timerRef: Performance.now()
|
|
294
294
|
};
|
|
295
295
|
}
|
|
296
|
-
return
|
|
296
|
+
return Performance.now();
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
function endOperation(timerRef, contract, event) {
|
|
@@ -305,10 +305,10 @@ function endOperation(timerRef, contract, event) {
|
|
|
305
305
|
let operationRef = operations[key];
|
|
306
306
|
operationRef.pendingCount = operationRef.pendingCount - 1 | 0;
|
|
307
307
|
if (operationRef.pendingCount === 0) {
|
|
308
|
-
handleFloat(timeCounter$1, labels,
|
|
308
|
+
handleFloat(timeCounter$1, labels, Performance.secondsSince(operationRef.timerRef));
|
|
309
309
|
Utils.Dict.deleteInPlace(operations, key);
|
|
310
310
|
}
|
|
311
|
-
handleFloat(sumTimeCounter, labels,
|
|
311
|
+
handleFloat(sumTimeCounter, labels, Performance.secondsSince(timerRef));
|
|
312
312
|
increment(count$1, labels);
|
|
313
313
|
}
|
|
314
314
|
|
|
@@ -775,10 +775,10 @@ function startOperation$1(storage, operation) {
|
|
|
775
775
|
} else {
|
|
776
776
|
operations$1[key] = {
|
|
777
777
|
pendingCount: 1,
|
|
778
|
-
timerRef:
|
|
778
|
+
timerRef: Performance.now()
|
|
779
779
|
};
|
|
780
780
|
}
|
|
781
|
-
return
|
|
781
|
+
return Performance.now();
|
|
782
782
|
}
|
|
783
783
|
|
|
784
784
|
function endOperation$1(timerRef, storage, operation, whereSize, size) {
|
|
@@ -790,10 +790,10 @@ function endOperation$1(timerRef, storage, operation, whereSize, size) {
|
|
|
790
790
|
let operationRef = operations$1[key];
|
|
791
791
|
operationRef.pendingCount = operationRef.pendingCount - 1 | 0;
|
|
792
792
|
if (operationRef.pendingCount === 0) {
|
|
793
|
-
handleFloat(timeCounter$7, labels,
|
|
793
|
+
handleFloat(timeCounter$7, labels, Performance.secondsSince(operationRef.timerRef));
|
|
794
794
|
Utils.Dict.deleteInPlace(operations$1, key);
|
|
795
795
|
}
|
|
796
|
-
handleFloat(sumTimeCounter$3, labels,
|
|
796
|
+
handleFloat(sumTimeCounter$3, labels, Performance.secondsSince(timerRef));
|
|
797
797
|
increment(counter$8, labels);
|
|
798
798
|
handleInt(whereSizeCounter, labels, whereSize);
|
|
799
799
|
handleInt(sizeCounter$1, labels, size);
|
|
@@ -14,7 +14,7 @@ let runPrune = async (state: IndexerState.t) => {
|
|
|
14
14
|
await Utils.delay(1000)
|
|
15
15
|
}
|
|
16
16
|
let entityConfig = persistence.allEntities->Array.getUnsafe(idx)
|
|
17
|
-
let timeRef =
|
|
17
|
+
let timeRef = Performance.now()
|
|
18
18
|
try {
|
|
19
19
|
let () = await persistence.storage.pruneStaleEntityHistory(
|
|
20
20
|
~entityName=entityConfig.name,
|
|
@@ -34,7 +34,7 @@ let runPrune = async (state: IndexerState.t) => {
|
|
|
34
34
|
)
|
|
35
35
|
}
|
|
36
36
|
Prometheus.RollbackHistoryPrune.increment(
|
|
37
|
-
~timeSeconds=
|
|
37
|
+
~timeSeconds=Performance.secondsSince(timeRef),
|
|
38
38
|
~entityName=entityConfig.name,
|
|
39
39
|
)
|
|
40
40
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Utils from "./Utils.res.mjs";
|
|
4
|
-
import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
5
4
|
import * as Logging from "./Logging.res.mjs";
|
|
6
5
|
import * as Throttler from "./Throttler.res.mjs";
|
|
7
6
|
import * as Prometheus from "./Prometheus.res.mjs";
|
|
7
|
+
import * as Performance from "./bindings/Performance.res.mjs";
|
|
8
8
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
9
9
|
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
10
10
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
@@ -21,7 +21,7 @@ async function runPrune(state) {
|
|
|
21
21
|
await Utils.delay(1000);
|
|
22
22
|
}
|
|
23
23
|
let entityConfig = persistence.allEntities[idx];
|
|
24
|
-
let timeRef =
|
|
24
|
+
let timeRef = Performance.now();
|
|
25
25
|
try {
|
|
26
26
|
await persistence.storage.pruneStaleEntityHistory(entityConfig.name, entityConfig.index, safeCheckpointId);
|
|
27
27
|
} catch (raw_exn) {
|
|
@@ -31,7 +31,7 @@ async function runPrune(state) {
|
|
|
31
31
|
safeCheckpointId: safeCheckpointId
|
|
32
32
|
}), `Failed to prune stale entity history`, exn);
|
|
33
33
|
}
|
|
34
|
-
Prometheus.RollbackHistoryPrune.increment(
|
|
34
|
+
Prometheus.RollbackHistoryPrune.increment(Performance.secondsSince(timeRef), entityConfig.name);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
package/src/Rollback.res
CHANGED
|
@@ -94,7 +94,7 @@ and executeRollback = async (
|
|
|
94
94
|
~scheduleFetch,
|
|
95
95
|
~scheduleProcessing,
|
|
96
96
|
) => {
|
|
97
|
-
let startTime =
|
|
97
|
+
let startTime = Performance.now()
|
|
98
98
|
|
|
99
99
|
let chainState = state->IndexerState.getChainState(~chain=reorgChain)
|
|
100
100
|
|
|
@@ -194,7 +194,7 @@ and executeRollback = async (
|
|
|
194
194
|
"targetCheckpointId": rollbackTargetCheckpointId,
|
|
195
195
|
})
|
|
196
196
|
Prometheus.RollbackSuccess.increment(
|
|
197
|
-
~timeSeconds=
|
|
197
|
+
~timeSeconds=Performance.secondsSince(startTime),
|
|
198
198
|
~rollbackedProcessedEvents=rollbackedProcessedEvents.contents,
|
|
199
199
|
)
|
|
200
200
|
|
package/src/Rollback.res.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Utils from "./Utils.res.mjs";
|
|
4
|
-
import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
5
4
|
import * as Logging from "./Logging.res.mjs";
|
|
6
5
|
import * as Writing from "./Writing.res.mjs";
|
|
7
6
|
import * as ChainState from "./ChainState.res.mjs";
|
|
8
7
|
import * as Prometheus from "./Prometheus.res.mjs";
|
|
8
|
+
import * as Performance from "./bindings/Performance.res.mjs";
|
|
9
9
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
10
10
|
import * as Stdlib_Float from "@rescript/runtime/lib/es6/Stdlib_Float.js";
|
|
11
11
|
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
@@ -32,7 +32,7 @@ async function getLastKnownValidBlock(chainState, reorgBlockNumber, isRealtime)
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
async function executeRollback(state, reorgChain, rollbackTargetBlockNumber, scheduleFetch, scheduleProcessing) {
|
|
35
|
-
let startTime =
|
|
35
|
+
let startTime = Performance.now();
|
|
36
36
|
let chainState = IndexerState.getChainState(state, reorgChain);
|
|
37
37
|
let logger = Logging.createChildFrom(ChainState.logger(chainState), {
|
|
38
38
|
action: "Rollback",
|
|
@@ -70,7 +70,7 @@ async function executeRollback(state, reorgChain, rollbackTargetBlockNumber, sch
|
|
|
70
70
|
beforeCheckpointId: IndexerState.committedCheckpointId(state),
|
|
71
71
|
targetCheckpointId: rollbackTargetCheckpointId
|
|
72
72
|
});
|
|
73
|
-
Prometheus.RollbackSuccess.increment(
|
|
73
|
+
Prometheus.RollbackSuccess.increment(Performance.secondsSince(startTime), rollbackedProcessedEvents);
|
|
74
74
|
IndexerState.completeRollback(state, eventsProcessedDiffByChain);
|
|
75
75
|
scheduleFetch();
|
|
76
76
|
return scheduleProcessing();
|
package/src/SimulateItems.res
CHANGED
|
@@ -195,6 +195,78 @@ let findEventConfig = (~config: Config.t, ~contractName: string, ~eventName: str
|
|
|
195
195
|
found.contents
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
let dummySrcAddress = Address.unsafeFromString("0x0000000000000000000000000000000000000000")
|
|
199
|
+
|
|
200
|
+
// First address configured for `contractName` on the simulated chain. Only the
|
|
201
|
+
// simulated chain is consulted — a contract's address on another chain has no
|
|
202
|
+
// meaning here.
|
|
203
|
+
let firstContractAddress = (~chainConfig: Config.chain, ~contractName: string): option<
|
|
204
|
+
Address.t,
|
|
205
|
+
> => {
|
|
206
|
+
let found = ref(None)
|
|
207
|
+
chainConfig.contracts->Array.forEach(contract => {
|
|
208
|
+
if found.contents->Option.isNone && contract.name === contractName {
|
|
209
|
+
found := contract.addresses->Array.get(0)
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
found.contents
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
let deriveSrcAddress = (
|
|
216
|
+
~providedSrcAddress: option<Address.t>,
|
|
217
|
+
~eventConfig: Internal.eventConfig,
|
|
218
|
+
~chainConfig: Config.chain,
|
|
219
|
+
): Address.t => {
|
|
220
|
+
switch providedSrcAddress {
|
|
221
|
+
| Some(addr) => addr
|
|
222
|
+
| None =>
|
|
223
|
+
if eventConfig.isWildcard {
|
|
224
|
+
dummySrcAddress
|
|
225
|
+
} else {
|
|
226
|
+
switch firstContractAddress(~chainConfig, ~contractName=eventConfig.contractName) {
|
|
227
|
+
| Some(addr) => addr
|
|
228
|
+
| None => dummySrcAddress
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// A non-wildcard event is gated by `clientAddressFilter` on srcAddress ownership,
|
|
235
|
+
// so a simulate item whose srcAddress isn't indexed on this chain would be
|
|
236
|
+
// silently dropped (handler never runs). Fail loudly instead.
|
|
237
|
+
let validateSrcAddresses = (
|
|
238
|
+
~simulateItems: array<JSON.t>,
|
|
239
|
+
~config: Config.t,
|
|
240
|
+
~chainConfig: Config.chain,
|
|
241
|
+
~indexingAddresses: array<Internal.indexingAddress>,
|
|
242
|
+
): unit => {
|
|
243
|
+
let known = Utils.Set.make()
|
|
244
|
+
indexingAddresses->Array.forEach(ia => known->Utils.Set.add(ia.address->Address.toString)->ignore)
|
|
245
|
+
simulateItems->Array.forEach(rawJson => {
|
|
246
|
+
let raw = rawJson->(Utils.magic: JSON.t => rawSimulateItem)
|
|
247
|
+
switch (raw->getContract, raw->getEvent) {
|
|
248
|
+
| (Some(contractName), Some(eventName)) =>
|
|
249
|
+
switch findEventConfig(~config, ~contractName, ~eventName) {
|
|
250
|
+
| Some(eventConfig) if !eventConfig.isWildcard =>
|
|
251
|
+
let item = rawJson->(Utils.magic: JSON.t => Envio.evmSimulateItem)
|
|
252
|
+
let srcAddress = deriveSrcAddress(
|
|
253
|
+
~providedSrcAddress=item.srcAddress,
|
|
254
|
+
~eventConfig,
|
|
255
|
+
~chainConfig,
|
|
256
|
+
)
|
|
257
|
+
if !(known->Utils.Set.has(srcAddress->Address.toString)) {
|
|
258
|
+
JsError.throwWithMessage(
|
|
259
|
+
`simulate: ${contractName}.${eventName} resolved to address ${srcAddress->Address.toString}, which isn't indexed on chain ${chainConfig.id->Int.toString}. ` ++
|
|
260
|
+
`Provide a "srcAddress" configured or registered for ${contractName} on this chain, or use a wildcard event.`,
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
| _ => ()
|
|
264
|
+
}
|
|
265
|
+
| _ => ()
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
198
270
|
let parse = (~simulateItems: array<JSON.t>, ~config: Config.t, ~chainConfig: Config.chain): array<
|
|
199
271
|
Internal.item,
|
|
200
272
|
> => {
|
|
@@ -238,21 +310,11 @@ let parse = (~simulateItems: array<JSON.t>, ~config: Config.t, ~chainConfig: Con
|
|
|
238
310
|
li
|
|
239
311
|
}
|
|
240
312
|
|
|
241
|
-
let srcAddress =
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
chainConfig.contracts->Array.forEach(contract => {
|
|
247
|
-
if contract.name === contractName {
|
|
248
|
-
switch contract.addresses->Array.get(0) {
|
|
249
|
-
| Some(a) => addr := a
|
|
250
|
-
| None => ()
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
})
|
|
254
|
-
addr.contents
|
|
255
|
-
}
|
|
313
|
+
let srcAddress = deriveSrcAddress(
|
|
314
|
+
~providedSrcAddress=item.srcAddress,
|
|
315
|
+
~eventConfig,
|
|
316
|
+
~chainConfig,
|
|
317
|
+
)
|
|
256
318
|
|
|
257
319
|
let rawItem = rawJson->(Utils.magic: JSON.t => {..})
|
|
258
320
|
let blockJson: option<JSON.t> =
|
|
@@ -135,6 +135,64 @@ function findEventConfig(config, contractName, eventName) {
|
|
|
135
135
|
return found.contents;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
let dummySrcAddress = "0x0000000000000000000000000000000000000000";
|
|
139
|
+
|
|
140
|
+
function firstContractAddress(chainConfig, contractName) {
|
|
141
|
+
let found = {
|
|
142
|
+
contents: undefined
|
|
143
|
+
};
|
|
144
|
+
chainConfig.contracts.forEach(contract => {
|
|
145
|
+
if (Stdlib_Option.isNone(found.contents) && contract.name === contractName) {
|
|
146
|
+
found.contents = contract.addresses[0];
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return found.contents;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function deriveSrcAddress(providedSrcAddress, eventConfig, chainConfig) {
|
|
154
|
+
if (providedSrcAddress !== undefined) {
|
|
155
|
+
return Primitive_option.valFromOption(providedSrcAddress);
|
|
156
|
+
}
|
|
157
|
+
if (eventConfig.isWildcard) {
|
|
158
|
+
return dummySrcAddress;
|
|
159
|
+
}
|
|
160
|
+
let addr = firstContractAddress(chainConfig, eventConfig.contractName);
|
|
161
|
+
if (addr !== undefined) {
|
|
162
|
+
return Primitive_option.valFromOption(addr);
|
|
163
|
+
} else {
|
|
164
|
+
return dummySrcAddress;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function validateSrcAddresses(simulateItems, config, chainConfig, indexingAddresses) {
|
|
169
|
+
let known = new Set();
|
|
170
|
+
indexingAddresses.forEach(ia => {
|
|
171
|
+
known.add(ia.address);
|
|
172
|
+
});
|
|
173
|
+
simulateItems.forEach(rawJson => {
|
|
174
|
+
let match = rawJson.contract;
|
|
175
|
+
let match$1 = rawJson.event;
|
|
176
|
+
if (match === undefined) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (match$1 === undefined) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
let eventConfig = findEventConfig(config, match, match$1);
|
|
183
|
+
if (eventConfig === undefined) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (eventConfig.isWildcard) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
let srcAddress = deriveSrcAddress(rawJson.srcAddress, eventConfig, chainConfig);
|
|
190
|
+
if (!known.has(srcAddress)) {
|
|
191
|
+
return Stdlib_JsError.throwWithMessage(`simulate: ` + match + `.` + match$1 + ` resolved to address ` + srcAddress + `, which isn't indexed on chain ` + chainConfig.id.toString() + `. ` + (`Provide a "srcAddress" configured or registered for ` + match + ` on this chain, or use a wildcard event.`));
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
138
196
|
function parse(simulateItems, config, chainConfig) {
|
|
139
197
|
let chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
|
|
140
198
|
let chainId = chainConfig.id;
|
|
@@ -169,26 +227,7 @@ function parse(simulateItems, config, chainConfig) {
|
|
|
169
227
|
currentLogIndex.contents = li$1 + 1 | 0;
|
|
170
228
|
logIndex = li$1;
|
|
171
229
|
}
|
|
172
|
-
let
|
|
173
|
-
let srcAddress;
|
|
174
|
-
if (addr !== undefined) {
|
|
175
|
-
srcAddress = Primitive_option.valFromOption(addr);
|
|
176
|
-
} else {
|
|
177
|
-
let addr$1 = {
|
|
178
|
-
contents: "0x0000000000000000000000000000000000000000"
|
|
179
|
-
};
|
|
180
|
-
chainConfig.contracts.forEach(contract => {
|
|
181
|
-
if (contract.name !== match) {
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
let a = contract.addresses[0];
|
|
185
|
-
if (a !== undefined) {
|
|
186
|
-
addr$1.contents = Primitive_option.valFromOption(a);
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
srcAddress = addr$1.contents;
|
|
191
|
-
}
|
|
230
|
+
let srcAddress = deriveSrcAddress(rawJson.srcAddress, eventConfig, chainConfig);
|
|
192
231
|
let blockJson = rawJson.block;
|
|
193
232
|
let blockJson$1 = (blockJson == null) ? undefined : Primitive_option.some(blockJson);
|
|
194
233
|
let transactionJson = rawJson.transaction;
|
|
@@ -318,6 +357,10 @@ export {
|
|
|
318
357
|
fuelSimulateTransactionSchema,
|
|
319
358
|
parseFuelSimulateTransaction,
|
|
320
359
|
findEventConfig,
|
|
360
|
+
dummySrcAddress,
|
|
361
|
+
firstContractAddress,
|
|
362
|
+
deriveSrcAddress,
|
|
363
|
+
validateSrcAddresses,
|
|
321
364
|
parse,
|
|
322
365
|
patchConfig,
|
|
323
366
|
}
|
package/src/TestIndexer.res
CHANGED
|
@@ -43,6 +43,33 @@ let toIndexingAddress = (dc: InternalTable.EnvioAddresses.t): Internal.indexingA
|
|
|
43
43
|
registrationBlock: dc.registrationBlock,
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// All indexing addresses (config-seeded + dynamically registered) grouped by
|
|
47
|
+
// chain id string, derived from the envio_addresses entities.
|
|
48
|
+
let getIndexingAddressesByChain = (state: testIndexerState): dict<
|
|
49
|
+
array<Internal.indexingAddress>,
|
|
50
|
+
> => {
|
|
51
|
+
let byChain = Dict.make()
|
|
52
|
+
switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
|
|
53
|
+
| Some(dcDict) =>
|
|
54
|
+
dcDict
|
|
55
|
+
->Dict.valuesToArray
|
|
56
|
+
->Array.forEach(entity => {
|
|
57
|
+
let dc = entity->castToEnvioAddresses
|
|
58
|
+
let chainIdStr = dc.chainId->Int.toString
|
|
59
|
+
let contracts = switch byChain->Dict.get(chainIdStr) {
|
|
60
|
+
| Some(arr) => arr
|
|
61
|
+
| None =>
|
|
62
|
+
let arr = []
|
|
63
|
+
byChain->Dict.set(chainIdStr, arr)
|
|
64
|
+
arr
|
|
65
|
+
}
|
|
66
|
+
contracts->Array.push(dc->toIndexingAddress)->ignore
|
|
67
|
+
})
|
|
68
|
+
| None => ()
|
|
69
|
+
}
|
|
70
|
+
byChain
|
|
71
|
+
}
|
|
72
|
+
|
|
46
73
|
let handleLoad = (state: testIndexerState, ~tableName: string, ~filter: EntityFilter.t): JSON.t => {
|
|
47
74
|
// Loads for non-entity tables (e.g. effect caches `envio_effect_<name>`) reach
|
|
48
75
|
// here too. TestIndexer never persists those, so there's nothing to return —
|
|
@@ -566,22 +593,10 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
|
|
|
566
593
|
`Cannot access ${contract.name}.addresses while indexer.process() is running. ` ++ "Wait for process() to complete before reading contract addresses.",
|
|
567
594
|
)
|
|
568
595
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
->Dict.valuesToArray
|
|
574
|
-
->Array.forEach(
|
|
575
|
-
entity => {
|
|
576
|
-
let dc = entity->castToEnvioAddresses
|
|
577
|
-
if dc.contractName === contract.name && dc.chainId === chainConfig.id {
|
|
578
|
-
addresses->Array.push(dc->Config.EnvioAddresses.getAddress)->ignore
|
|
579
|
-
}
|
|
580
|
-
},
|
|
581
|
-
)
|
|
582
|
-
| None => ()
|
|
583
|
-
}
|
|
584
|
-
addresses
|
|
596
|
+
getIndexingAddressesByChain(state)
|
|
597
|
+
->Dict.get(chainConfig.id->Int.toString)
|
|
598
|
+
->Option.getOr([])
|
|
599
|
+
->Array.filterMap(ia => ia.contractName === contract.name ? Some(ia.address) : None)
|
|
585
600
|
},
|
|
586
601
|
},
|
|
587
602
|
)
|
|
@@ -653,6 +668,7 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
|
|
|
653
668
|
})
|
|
654
669
|
|
|
655
670
|
// Parse and validate all chain configs upfront before starting any workers
|
|
671
|
+
let preflightAddressesByChain = getIndexingAddressesByChain(state)
|
|
656
672
|
let chainEntries = sortedChainKeys->Array.map(chainIdStr => {
|
|
657
673
|
let rawChainConfig = rawChains->Dict.getUnsafe(chainIdStr)
|
|
658
674
|
let chainId = switch chainIdStr->Int.fromString {
|
|
@@ -668,6 +684,19 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
|
|
|
668
684
|
~rawChainConfig,
|
|
669
685
|
~progressBlock=state.progressBlockByChain->Dict.get(chainIdStr),
|
|
670
686
|
)
|
|
687
|
+
switch rawChainConfig.simulate {
|
|
688
|
+
| Some(simulateItems) =>
|
|
689
|
+
let chainConfig = config.chainMap->ChainMap.get(ChainMap.Chain.makeUnsafe(~chainId))
|
|
690
|
+
SimulateItems.validateSrcAddresses(
|
|
691
|
+
~simulateItems,
|
|
692
|
+
~config,
|
|
693
|
+
~chainConfig,
|
|
694
|
+
~indexingAddresses=preflightAddressesByChain
|
|
695
|
+
->Dict.get(chainIdStr)
|
|
696
|
+
->Option.getOr([]),
|
|
697
|
+
)
|
|
698
|
+
| None => ()
|
|
699
|
+
}
|
|
671
700
|
(chainIdStr, chainId, rawChainConfig, processChainConfig)
|
|
672
701
|
})
|
|
673
702
|
|
|
@@ -684,26 +713,9 @@ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
|
|
|
684
713
|
let chains: dict<chainConfig> = Dict.make()
|
|
685
714
|
chains->Dict.set(chainIdStr, processChainConfig)
|
|
686
715
|
|
|
687
|
-
//
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
| Some(dcDict) =>
|
|
691
|
-
dcDict
|
|
692
|
-
->Dict.valuesToArray
|
|
693
|
-
->Array.forEach(entity => {
|
|
694
|
-
let dc = entity->castToEnvioAddresses
|
|
695
|
-
let dcChainIdStr = dc.chainId->Int.toString
|
|
696
|
-
let contracts = switch indexingAddressesByChain->Dict.get(dcChainIdStr) {
|
|
697
|
-
| Some(arr) => arr
|
|
698
|
-
| None =>
|
|
699
|
-
let arr = []
|
|
700
|
-
indexingAddressesByChain->Dict.set(dcChainIdStr, arr)
|
|
701
|
-
arr
|
|
702
|
-
}
|
|
703
|
-
contracts->Array.push(dc->toIndexingAddress)->ignore
|
|
704
|
-
})
|
|
705
|
-
| None => ()
|
|
706
|
-
}
|
|
716
|
+
// Rebuilt per chain so workers see contracts registered by earlier
|
|
717
|
+
// chains in the same process() call.
|
|
718
|
+
let indexingAddressesByChain = getIndexingAddressesByChain(state)
|
|
707
719
|
|
|
708
720
|
let initialState = makeInitialState(
|
|
709
721
|
~config,
|