envio 3.3.0-alpha.10 → 3.3.0-alpha.12
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/licenses/CLA.md +35 -0
- package/licenses/EULA.md +67 -0
- package/licenses/LICENSE.md +45 -0
- package/licenses/README.md +35 -0
- package/package.json +9 -8
- package/src/Batch.res.mjs +1 -1
- package/src/ChainFetching.res +30 -18
- package/src/ChainFetching.res.mjs +23 -13
- package/src/ChainState.res +45 -30
- package/src/ChainState.res.mjs +22 -8
- package/src/ChainState.resi +5 -0
- package/src/Config.res +9 -5
- package/src/Config.res.mjs +2 -2
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +12 -0
- package/src/CrossChainState.res +64 -29
- package/src/CrossChainState.res.mjs +17 -8
- package/src/EventConfigBuilder.res +21 -46
- package/src/EventConfigBuilder.res.mjs +18 -25
- package/src/EventProcessing.res +8 -5
- package/src/EventProcessing.res.mjs +2 -1
- package/src/FetchState.res +428 -322
- package/src/FetchState.res.mjs +316 -233
- package/src/HandlerRegister.res +3 -1
- package/src/HandlerRegister.res.mjs +3 -2
- package/src/Internal.res +11 -2
- package/src/LogSelection.res +0 -62
- package/src/LogSelection.res.mjs +0 -74
- package/src/RawEvent.res +2 -2
- package/src/Rollback.res +32 -13
- package/src/Rollback.res.mjs +24 -11
- package/src/SimulateDeadInputTracker.res +1 -1
- package/src/SimulateItems.res +38 -6
- package/src/SimulateItems.res.mjs +28 -9
- package/src/TestIndexer.res +2 -2
- package/src/TestIndexer.res.mjs +2 -2
- package/src/TopicFilter.res +1 -25
- package/src/TopicFilter.res.mjs +0 -74
- package/src/bindings/Viem.res +0 -5
- package/src/sources/EventRouter.res +0 -21
- package/src/sources/EventRouter.res.mjs +0 -12
- package/src/sources/EvmChain.res +2 -27
- package/src/sources/EvmChain.res.mjs +2 -23
- package/src/sources/EvmRpcClient.res +12 -15
- package/src/sources/EvmRpcClient.res.mjs +3 -3
- package/src/sources/HyperSync.res +9 -38
- package/src/sources/HyperSync.res.mjs +16 -28
- package/src/sources/HyperSync.resi +2 -2
- package/src/sources/HyperSyncClient.res +88 -11
- package/src/sources/HyperSyncClient.res.mjs +39 -6
- package/src/sources/HyperSyncSource.res +18 -199
- package/src/sources/HyperSyncSource.res.mjs +9 -128
- package/src/sources/Rpc.res +0 -32
- package/src/sources/Rpc.res.mjs +1 -46
- package/src/sources/RpcSource.res +29 -175
- package/src/sources/RpcSource.res.mjs +32 -110
- package/src/sources/SimulateSource.res +37 -19
- package/src/sources/SimulateSource.res.mjs +27 -10
- package/src/sources/SvmHyperSyncSource.res +13 -3
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
|
@@ -97,10 +97,6 @@ let getErrorMessage = (exn: exn): option<string> =>
|
|
|
97
97
|
| _ => None
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
type logSelection = {
|
|
101
|
-
addresses: option<array<Address.t>>,
|
|
102
|
-
topicQuery: Rpc.GetLogs.topicQuery,
|
|
103
|
-
}
|
|
104
100
|
|
|
105
101
|
// `EvmRpcClient.getNextPage` throws a napi error whose message is a JSON
|
|
106
102
|
// payload describing the retry decision:
|
|
@@ -161,122 +157,6 @@ let parseGetNextPageRetryError = (exn: exn): option<(
|
|
|
161
157
|
| _ => None
|
|
162
158
|
}
|
|
163
159
|
|
|
164
|
-
type selectionConfig = {
|
|
165
|
-
getLogSelectionsOrThrow: (
|
|
166
|
-
~addressesByContractName: dict<array<Address.t>>,
|
|
167
|
-
) => array<logSelection>,
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
let getSelectionConfig = (selection: FetchState.selection) => {
|
|
171
|
-
let evmOnEventRegistrations =
|
|
172
|
-
selection.onEventRegistrations->(
|
|
173
|
-
Utils.magic: array<Internal.onEventRegistration> => array<Internal.evmOnEventRegistration>
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
if evmOnEventRegistrations->Utils.Array.isEmpty {
|
|
177
|
-
throw(
|
|
178
|
-
Source.GetItemsError(
|
|
179
|
-
UnsupportedSelection({
|
|
180
|
-
message: "Invalid events configuration for the partition. Nothing to fetch. Please, report to the Envio team.",
|
|
181
|
-
}),
|
|
182
|
-
),
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// eth_getLogs takes one address list and one topic selection per request, so
|
|
187
|
-
// fan out to one request per selection. Each address-bound event is grouped by
|
|
188
|
-
// its contract and later scoped to that contract's own addresses — pooling all
|
|
189
|
-
// contracts' addresses would let one contract's query fetch a sibling's logs,
|
|
190
|
-
// which route back by address and bypass the sibling's filter (routing never
|
|
191
|
-
// re-applies it). Pure-wildcard events carry no address constraint, so they're
|
|
192
|
-
// pooled and resolved once.
|
|
193
|
-
let noAddressTopicSelections = []
|
|
194
|
-
let byContract = Dict.make()
|
|
195
|
-
let wildcardByContract = Dict.make()
|
|
196
|
-
let contractNames = Utils.Set.make()
|
|
197
|
-
|
|
198
|
-
evmOnEventRegistrations->Array.forEach(reg => {
|
|
199
|
-
let contractName = reg.eventConfig.contractName
|
|
200
|
-
let {isWildcard, dependsOnAddresses, resolvedWhere} = reg
|
|
201
|
-
if dependsOnAddresses {
|
|
202
|
-
contractNames->Utils.Set.add(contractName)->ignore
|
|
203
|
-
(isWildcard ? wildcardByContract : byContract)->Utils.Dict.pushMany(
|
|
204
|
-
contractName,
|
|
205
|
-
resolvedWhere.topicSelections,
|
|
206
|
-
)
|
|
207
|
-
} else {
|
|
208
|
-
noAddressTopicSelections
|
|
209
|
-
->Array.pushMany(
|
|
210
|
-
resolvedWhere.topicSelections->LogSelection.materializeTopicSelections(~addresses=[]),
|
|
211
|
-
)
|
|
212
|
-
->ignore
|
|
213
|
-
}
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
// `compressTopicSelections` folds the filter-less events into a single topic0
|
|
217
|
-
// OR-set, keeping the common case at one request.
|
|
218
|
-
let toLogSelections = (~addresses, topicSelections): array<logSelection> =>
|
|
219
|
-
topicSelections
|
|
220
|
-
->LogSelection.compressTopicSelections
|
|
221
|
-
->Array.map(topicSelection => {
|
|
222
|
-
addresses,
|
|
223
|
-
topicQuery: topicSelection->Rpc.GetLogs.mapTopicQuery,
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
// Address-independent, so resolve once (the wildcard partition reuses this).
|
|
227
|
-
let noAddressLogSelections = toLogSelections(~addresses=None, noAddressTopicSelections)
|
|
228
|
-
|
|
229
|
-
let getLogSelectionsOrThrow = if contractNames->Utils.Set.size === 0 {
|
|
230
|
-
(~addressesByContractName as _) => noAddressLogSelections
|
|
231
|
-
} else {
|
|
232
|
-
(~addressesByContractName): array<logSelection> => {
|
|
233
|
-
let logSelections = noAddressLogSelections->Array.copy
|
|
234
|
-
contractNames->Utils.Set.forEach(contractName => {
|
|
235
|
-
switch addressesByContractName->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
236
|
-
| None
|
|
237
|
-
| Some([]) => ()
|
|
238
|
-
| Some(addresses) =>
|
|
239
|
-
// Non-wildcard filters, scoped to this contract's addresses.
|
|
240
|
-
switch byContract->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
241
|
-
| Some(topicSelections) =>
|
|
242
|
-
logSelections
|
|
243
|
-
->Array.pushMany(
|
|
244
|
-
toLogSelections(
|
|
245
|
-
~addresses=Some(addresses),
|
|
246
|
-
topicSelections->LogSelection.materializeTopicSelections(~addresses),
|
|
247
|
-
),
|
|
248
|
-
)
|
|
249
|
-
->ignore
|
|
250
|
-
| None => ()
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Wildcard-by-address filters fold the address into the topics,
|
|
254
|
-
// so they still match any address.
|
|
255
|
-
switch wildcardByContract->Utils.Dict.dangerouslyGetNonOption(contractName) {
|
|
256
|
-
| Some(topicSelections) =>
|
|
257
|
-
logSelections
|
|
258
|
-
->Array.pushMany(
|
|
259
|
-
toLogSelections(
|
|
260
|
-
~addresses=None,
|
|
261
|
-
topicSelections->LogSelection.materializeTopicSelections(~addresses),
|
|
262
|
-
),
|
|
263
|
-
)
|
|
264
|
-
->ignore
|
|
265
|
-
| None => ()
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
})
|
|
269
|
-
logSelections
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
{
|
|
274
|
-
getLogSelectionsOrThrow: getLogSelectionsOrThrow,
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
let memoGetSelectionConfig = () => Utils.WeakMap.memoize(getSelectionConfig)
|
|
279
|
-
|
|
280
160
|
// Type-erase a schema for storage in the field registry
|
|
281
161
|
external toFieldSchema: S.t<'a> => S.t<JSON.t> = "%identity"
|
|
282
162
|
|
|
@@ -735,8 +615,8 @@ type options = {
|
|
|
735
615
|
syncConfig: Config.sourceSync,
|
|
736
616
|
url: string,
|
|
737
617
|
chain: ChainMap.Chain.t,
|
|
738
|
-
|
|
739
|
-
|
|
618
|
+
// The chain's registrations, indexed by their sequential `index`.
|
|
619
|
+
onEventRegistrations: array<Internal.evmOnEventRegistration>,
|
|
740
620
|
lowercaseAddresses: bool,
|
|
741
621
|
ws?: string,
|
|
742
622
|
headers?: dict<string>,
|
|
@@ -748,8 +628,7 @@ let make = (
|
|
|
748
628
|
syncConfig,
|
|
749
629
|
url,
|
|
750
630
|
chain,
|
|
751
|
-
|
|
752
|
-
allEventParams,
|
|
631
|
+
onEventRegistrations,
|
|
753
632
|
lowercaseAddresses,
|
|
754
633
|
?ws,
|
|
755
634
|
?headers,
|
|
@@ -765,12 +644,12 @@ let make = (
|
|
|
765
644
|
}
|
|
766
645
|
let name = `RPC (${urlHost})`
|
|
767
646
|
|
|
768
|
-
let getSelectionConfig = memoGetSelectionConfig()
|
|
769
|
-
|
|
770
647
|
let client = Rpc.makeClient(url, ~headers?)
|
|
771
648
|
let rpcClient = EvmRpcClient.make(
|
|
772
649
|
~url,
|
|
773
|
-
~
|
|
650
|
+
~eventRegistrations=HyperSyncClient.Registration.fromOnEventRegistrations(
|
|
651
|
+
onEventRegistrations,
|
|
652
|
+
),
|
|
774
653
|
~checksumAddresses=!lowercaseAddresses,
|
|
775
654
|
~syncConfig,
|
|
776
655
|
~headers?,
|
|
@@ -921,7 +800,7 @@ let make = (
|
|
|
921
800
|
~fromBlock,
|
|
922
801
|
~toBlock,
|
|
923
802
|
~addressesByContractName,
|
|
924
|
-
~contractNameByAddress,
|
|
803
|
+
~contractNameByAddress as _,
|
|
925
804
|
~knownHeight,
|
|
926
805
|
~partitionId,
|
|
927
806
|
~selection: FetchState.selection,
|
|
@@ -944,26 +823,22 @@ let make = (
|
|
|
944
823
|
->Promise.thenResolve(json => Some(parseBlockInfo(json)))
|
|
945
824
|
: Promise.resolve(None)
|
|
946
825
|
|
|
947
|
-
|
|
948
|
-
|
|
826
|
+
if selection.onEventRegistrations->Utils.Array.isEmpty {
|
|
827
|
+
throw(
|
|
828
|
+
Source.GetItemsError(
|
|
829
|
+
UnsupportedSelection({
|
|
830
|
+
message: "Invalid events configuration for the partition. Nothing to fetch. Please, report to the Envio team.",
|
|
831
|
+
}),
|
|
832
|
+
),
|
|
833
|
+
)
|
|
834
|
+
}
|
|
949
835
|
|
|
950
836
|
let {items, toBlock: queriedToBlock, requestStats} = try await rpcClient.getNextPage({
|
|
951
837
|
fromBlock,
|
|
952
838
|
toBlockCeiling: toBlock,
|
|
953
|
-
logSelections: logSelections->Array.map(({
|
|
954
|
-
addresses,
|
|
955
|
-
topicQuery,
|
|
956
|
-
}): EvmRpcClient.logSelectionInput => {
|
|
957
|
-
?addresses,
|
|
958
|
-
topics: topicQuery->Array.map(filter =>
|
|
959
|
-
switch filter {
|
|
960
|
-
| Rpc.GetLogs.Null => Nullable.null
|
|
961
|
-
| Single(topic) => Nullable.make([topic])
|
|
962
|
-
| Multiple(topics) => Nullable.make(topics)
|
|
963
|
-
}
|
|
964
|
-
),
|
|
965
|
-
}),
|
|
966
839
|
partitionId,
|
|
840
|
+
registrationIndexes: selection.onEventRegistrations->Array.map(reg => reg.index),
|
|
841
|
+
addressesByContractName,
|
|
967
842
|
}) catch {
|
|
968
843
|
| exn =>
|
|
969
844
|
switch exn->parseGetNextPageRetryError {
|
|
@@ -997,32 +872,15 @@ let make = (
|
|
|
997
872
|
->Promise.thenResolve(parseBlockInfo)
|
|
998
873
|
|
|
999
874
|
let parsedQueueItems = await items
|
|
1000
|
-
->Array.
|
|
1001
|
-
|
|
1002
|
-
let
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
~tag=EventRouter.getEvmEventId(~sighash=topic0, ~topicCount=log.topics->Array.length),
|
|
1010
|
-
~contractNameByAddress,
|
|
1011
|
-
~contractAddress=routedAddress,
|
|
1012
|
-
) {
|
|
1013
|
-
| None => None
|
|
1014
|
-
| Some(onEventRegistration) =>
|
|
1015
|
-
let eventConfig =
|
|
1016
|
-
onEventRegistration.eventConfig->(
|
|
1017
|
-
Utils.magic: Internal.eventConfig => Internal.evmEventConfig
|
|
1018
|
-
)
|
|
1019
|
-
switch maybeDecodedEvent
|
|
1020
|
-
->Nullable.toOption
|
|
1021
|
-
->Option.flatMap(Dict.get(_, eventConfig.contractName)) {
|
|
1022
|
-
| Some(decoded) =>
|
|
1023
|
-
Some(
|
|
1024
|
-
(
|
|
1025
|
-
async () => {
|
|
875
|
+
->Array.map(({log, onEventRegistrationIndex, params: decoded}: EvmRpcClient.rpcEventItem) => {
|
|
876
|
+
// `log.address` comes back already normalized to the client's casing.
|
|
877
|
+
let onEventRegistration = onEventRegistrations->Array.getUnsafe(onEventRegistrationIndex)
|
|
878
|
+
let eventConfig =
|
|
879
|
+
onEventRegistration.eventConfig->(
|
|
880
|
+
Utils.magic: Internal.eventConfig => Internal.evmEventConfig
|
|
881
|
+
)
|
|
882
|
+
(
|
|
883
|
+
async () => {
|
|
1026
884
|
let (block, transaction) = try await Promise.all2((
|
|
1027
885
|
log->getEventBlockOrThrow(~selectedBlockFields=eventConfig.selectedBlockFields),
|
|
1028
886
|
log->getEventTransactionOrThrow(
|
|
@@ -1074,16 +932,12 @@ let make = (
|
|
|
1074
932
|
params: decoded,
|
|
1075
933
|
block,
|
|
1076
934
|
transaction,
|
|
1077
|
-
srcAddress:
|
|
935
|
+
srcAddress: log.address,
|
|
1078
936
|
logIndex: log.logIndex,
|
|
1079
937
|
}->Evm.fromPayload,
|
|
1080
938
|
})
|
|
1081
|
-
}
|
|
1082
|
-
)(),
|
|
1083
|
-
)
|
|
1084
|
-
| None => None
|
|
1085
939
|
}
|
|
1086
|
-
|
|
940
|
+
)()
|
|
1087
941
|
})
|
|
1088
942
|
->Promise.all
|
|
1089
943
|
|
|
@@ -9,17 +9,16 @@ import * as Address from "../Address.res.mjs";
|
|
|
9
9
|
import * as Logging from "../Logging.res.mjs";
|
|
10
10
|
import * as Internal from "../Internal.res.mjs";
|
|
11
11
|
import * as LazyLoader from "../LazyLoader.res.mjs";
|
|
12
|
-
import * as EventRouter from "./EventRouter.res.mjs";
|
|
13
12
|
import * as Performance from "../bindings/Performance.res.mjs";
|
|
14
13
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
15
14
|
import * as EvmRpcClient from "./EvmRpcClient.res.mjs";
|
|
16
|
-
import * as LogSelection from "../LogSelection.res.mjs";
|
|
17
15
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
18
16
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
19
17
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
20
18
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
21
19
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
22
20
|
import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
|
|
21
|
+
import * as HyperSyncClient from "./HyperSyncClient.res.mjs";
|
|
23
22
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
24
23
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
25
24
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
@@ -193,69 +192,6 @@ function parseGetNextPageRetryError(exn) {
|
|
|
193
192
|
]);
|
|
194
193
|
}
|
|
195
194
|
|
|
196
|
-
function getSelectionConfig(selection) {
|
|
197
|
-
let evmOnEventRegistrations = selection.onEventRegistrations;
|
|
198
|
-
if (Utils.$$Array.isEmpty(evmOnEventRegistrations)) {
|
|
199
|
-
throw {
|
|
200
|
-
RE_EXN_ID: Source.GetItemsError,
|
|
201
|
-
_1: {
|
|
202
|
-
TAG: "UnsupportedSelection",
|
|
203
|
-
message: "Invalid events configuration for the partition. Nothing to fetch. Please, report to the Envio team."
|
|
204
|
-
},
|
|
205
|
-
Error: new Error()
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
let noAddressTopicSelections = [];
|
|
209
|
-
let byContract = {};
|
|
210
|
-
let wildcardByContract = {};
|
|
211
|
-
let contractNames = new Set();
|
|
212
|
-
evmOnEventRegistrations.forEach(reg => {
|
|
213
|
-
let contractName = reg.eventConfig.contractName;
|
|
214
|
-
let resolvedWhere = reg.resolvedWhere;
|
|
215
|
-
if (reg.dependsOnAddresses) {
|
|
216
|
-
contractNames.add(contractName);
|
|
217
|
-
return Utils.Dict.pushMany(reg.isWildcard ? wildcardByContract : byContract, contractName, resolvedWhere.topicSelections);
|
|
218
|
-
} else {
|
|
219
|
-
noAddressTopicSelections.push(...LogSelection.materializeTopicSelections(resolvedWhere.topicSelections, []));
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
let toLogSelections = (addresses, topicSelections) => LogSelection.compressTopicSelections(topicSelections).map(topicSelection => ({
|
|
224
|
-
addresses: addresses,
|
|
225
|
-
topicQuery: Rpc.GetLogs.mapTopicQuery(topicSelection)
|
|
226
|
-
}));
|
|
227
|
-
let noAddressLogSelections = toLogSelections(undefined, noAddressTopicSelections);
|
|
228
|
-
let getLogSelectionsOrThrow = contractNames.size === 0 ? param => noAddressLogSelections : addressesByContractName => {
|
|
229
|
-
let logSelections = noAddressLogSelections.slice();
|
|
230
|
-
contractNames.forEach(contractName => {
|
|
231
|
-
let addresses = addressesByContractName[contractName];
|
|
232
|
-
if (addresses === undefined) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
if (addresses.length === 0) {
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
let topicSelections = byContract[contractName];
|
|
239
|
-
if (topicSelections !== undefined) {
|
|
240
|
-
logSelections.push(...toLogSelections(addresses, LogSelection.materializeTopicSelections(topicSelections, addresses)));
|
|
241
|
-
}
|
|
242
|
-
let topicSelections$1 = wildcardByContract[contractName];
|
|
243
|
-
if (topicSelections$1 !== undefined) {
|
|
244
|
-
logSelections.push(...toLogSelections(undefined, LogSelection.materializeTopicSelections(topicSelections$1, addresses)));
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
return logSelections;
|
|
249
|
-
};
|
|
250
|
-
return {
|
|
251
|
-
getLogSelectionsOrThrow: getLogSelectionsOrThrow
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function memoGetSelectionConfig() {
|
|
256
|
-
return Utils.$$WeakMap.memoize(getSelectionConfig);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
195
|
let lowercaseAddressSchema = S$RescriptSchema.transform(S$RescriptSchema.string, param => ({
|
|
260
196
|
p: str => str.toLowerCase()
|
|
261
197
|
}));
|
|
@@ -790,16 +726,15 @@ function makeThrowingGetEventTransaction(getTransactionJson, getReceiptJson, low
|
|
|
790
726
|
function make(param) {
|
|
791
727
|
let headers = param.headers;
|
|
792
728
|
let lowercaseAddresses = param.lowercaseAddresses;
|
|
793
|
-
let
|
|
729
|
+
let onEventRegistrations = param.onEventRegistrations;
|
|
794
730
|
let chain = param.chain;
|
|
795
731
|
let url = param.url;
|
|
796
732
|
let syncConfig = param.syncConfig;
|
|
797
733
|
let host = Utils.Url.getHostFromUrl(url);
|
|
798
734
|
let urlHost = host !== undefined ? host : Stdlib_JsError.throwWithMessage(`The RPC url for chain ` + chain.toString() + ` is in incorrect format. The RPC url needs to start with either http:// or https://`);
|
|
799
735
|
let name = `RPC (` + urlHost + `)`;
|
|
800
|
-
let getSelectionConfig$1 = Utils.$$WeakMap.memoize(getSelectionConfig);
|
|
801
736
|
let client = Rpc.makeClient(url, headers);
|
|
802
|
-
let rpcClient = EvmRpcClient.make(url, !lowercaseAddresses, syncConfig, undefined, headers,
|
|
737
|
+
let rpcClient = EvmRpcClient.make(url, !lowercaseAddresses, syncConfig, undefined, headers, HyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations));
|
|
803
738
|
let pendingRequestStats = [];
|
|
804
739
|
let recordRequest = (method, seconds) => {
|
|
805
740
|
pendingRequestStats.push({
|
|
@@ -885,43 +820,41 @@ function make(param) {
|
|
|
885
820
|
Error: new Error()
|
|
886
821
|
};
|
|
887
822
|
}, lowercaseAddresses);
|
|
888
|
-
let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName,
|
|
823
|
+
let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, param, knownHeight, partitionId, selection, param$1, retry, param$2) => {
|
|
889
824
|
let startFetchingBatchTimeRef = Performance.now();
|
|
890
825
|
let toBlock$1 = toBlock !== undefined ? Primitive_int.min(toBlock, knownHeight) : knownHeight;
|
|
891
826
|
let firstBlockParentPromise = fromBlock > 0 ? LazyLoader.get(blockLoader.contents, fromBlock - 1 | 0).then(json => parseBlockInfo(json)) : Promise.resolve(undefined);
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
827
|
+
if (Utils.$$Array.isEmpty(selection.onEventRegistrations)) {
|
|
828
|
+
throw {
|
|
829
|
+
RE_EXN_ID: Source.GetItemsError,
|
|
830
|
+
_1: {
|
|
831
|
+
TAG: "UnsupportedSelection",
|
|
832
|
+
message: "Invalid events configuration for the partition. Nothing to fetch. Please, report to the Envio team."
|
|
833
|
+
},
|
|
834
|
+
Error: new Error()
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
let match;
|
|
895
838
|
try {
|
|
896
|
-
match
|
|
839
|
+
match = await rpcClient.getNextPage({
|
|
897
840
|
fromBlock: fromBlock,
|
|
898
841
|
toBlockCeiling: toBlock$1,
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
if (filter === null) {
|
|
903
|
-
return null;
|
|
904
|
-
} else if (typeof filter === "string") {
|
|
905
|
-
return [filter];
|
|
906
|
-
} else {
|
|
907
|
-
return filter;
|
|
908
|
-
}
|
|
909
|
-
})
|
|
910
|
-
})),
|
|
911
|
-
partitionId: partitionId
|
|
842
|
+
partitionId: partitionId,
|
|
843
|
+
registrationIndexes: selection.onEventRegistrations.map(reg => reg.index),
|
|
844
|
+
addressesByContractName: addressesByContractName
|
|
912
845
|
});
|
|
913
846
|
} catch (raw_exn) {
|
|
914
847
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
915
|
-
let match$
|
|
916
|
-
if (match$
|
|
917
|
-
match$
|
|
848
|
+
let match$1 = parseGetNextPageRetryError(exn);
|
|
849
|
+
if (match$1 !== undefined) {
|
|
850
|
+
match$1[2].forEach(stat => recordRequest(stat.method, stat.seconds));
|
|
918
851
|
throw {
|
|
919
852
|
RE_EXN_ID: Source.GetItemsError,
|
|
920
853
|
_1: {
|
|
921
854
|
TAG: "FailedGettingItems",
|
|
922
855
|
exn: exn,
|
|
923
|
-
attemptedToBlock: match$
|
|
924
|
-
retry: match$
|
|
856
|
+
attemptedToBlock: match$1[0],
|
|
857
|
+
retry: match$1[1]
|
|
925
858
|
},
|
|
926
859
|
Error: new Error()
|
|
927
860
|
};
|
|
@@ -941,23 +874,14 @@ function make(param) {
|
|
|
941
874
|
Error: new Error()
|
|
942
875
|
};
|
|
943
876
|
}
|
|
944
|
-
let items = match
|
|
945
|
-
match
|
|
946
|
-
let latestFetchedBlockInfo = await LazyLoader.get(blockLoader.contents, match
|
|
947
|
-
let parsedQueueItems = await Promise.all(
|
|
877
|
+
let items = match.items;
|
|
878
|
+
match.requestStats.forEach(stat => recordRequest(stat.method, stat.seconds));
|
|
879
|
+
let latestFetchedBlockInfo = await LazyLoader.get(blockLoader.contents, match.toBlock).then(parseBlockInfo);
|
|
880
|
+
let parsedQueueItems = await Promise.all(items.map(param => {
|
|
881
|
+
let decoded = param.params;
|
|
948
882
|
let log = param.log;
|
|
949
|
-
let
|
|
950
|
-
let routedAddress = lowercaseAddresses ? Address.Evm.fromAddressLowercaseOrThrow(log.address) : Address.Evm.fromAddressOrThrow(log.address);
|
|
951
|
-
let onEventRegistration = EventRouter.get(eventRouter, EventRouter.getEvmEventId(topic0, log.topics.length), routedAddress, contractNameByAddress);
|
|
952
|
-
if (onEventRegistration === undefined) {
|
|
953
|
-
return;
|
|
954
|
-
}
|
|
883
|
+
let onEventRegistration = onEventRegistrations[param.onEventRegistrationIndex];
|
|
955
884
|
let eventConfig = onEventRegistration.eventConfig;
|
|
956
|
-
let decoded = Stdlib_Option.flatMap(Primitive_option.fromNullable(param.params), __x => __x[eventConfig.contractName]);
|
|
957
|
-
if (decoded === undefined) {
|
|
958
|
-
return;
|
|
959
|
-
}
|
|
960
|
-
let decoded$1 = Primitive_option.valFromOption(decoded);
|
|
961
885
|
return (async () => {
|
|
962
886
|
let match;
|
|
963
887
|
try {
|
|
@@ -1007,9 +931,9 @@ function make(param) {
|
|
|
1007
931
|
payload: {
|
|
1008
932
|
contractName: eventConfig.contractName,
|
|
1009
933
|
eventName: eventConfig.name,
|
|
1010
|
-
params: decoded
|
|
934
|
+
params: decoded,
|
|
1011
935
|
chainId: chain,
|
|
1012
|
-
srcAddress:
|
|
936
|
+
srcAddress: log.address,
|
|
1013
937
|
logIndex: log.logIndex,
|
|
1014
938
|
transaction: Primitive_option.some(match[1]),
|
|
1015
939
|
block: Primitive_option.some(block)
|
|
@@ -1123,8 +1047,6 @@ export {
|
|
|
1123
1047
|
getKnownRawBlockWithBackoff,
|
|
1124
1048
|
getErrorMessage,
|
|
1125
1049
|
parseGetNextPageRetryError,
|
|
1126
|
-
getSelectionConfig,
|
|
1127
|
-
memoGetSelectionConfig,
|
|
1128
1050
|
lowercaseAddressSchema,
|
|
1129
1051
|
checksumAddressSchema,
|
|
1130
1052
|
makeBlockFieldRegistry,
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain.t): Source.t => {
|
|
2
|
-
|
|
3
|
-
// Return all items on the first call and empty on subsequent calls to prevent
|
|
4
|
-
// duplicate event processing.
|
|
5
|
-
let delivered = ref(false)
|
|
2
|
+
let reportedHeight = max(endBlock, 1)
|
|
6
3
|
|
|
7
4
|
{
|
|
8
5
|
name: "SimulateSource",
|
|
@@ -16,38 +13,59 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
|
|
|
16
13
|
},
|
|
17
14
|
getHeightOrThrow: () => {
|
|
18
15
|
// Report at least height 1 so the engine doesn't treat 0 as "no blocks available"
|
|
19
|
-
Promise.resolve({Source.height:
|
|
16
|
+
Promise.resolve({Source.height: reportedHeight, requestStats: []})
|
|
20
17
|
},
|
|
21
18
|
getItemsOrThrow: (
|
|
22
|
-
~fromBlock
|
|
23
|
-
~toBlock
|
|
19
|
+
~fromBlock,
|
|
20
|
+
~toBlock,
|
|
24
21
|
~addressesByContractName as _,
|
|
25
|
-
~contractNameByAddress
|
|
22
|
+
~contractNameByAddress,
|
|
26
23
|
~knownHeight as _,
|
|
27
24
|
~partitionId as _,
|
|
28
|
-
~selection
|
|
25
|
+
~selection: FetchState.selection,
|
|
29
26
|
~itemsTarget as _,
|
|
30
27
|
~retry as _,
|
|
31
28
|
~logger as _,
|
|
32
29
|
) => {
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
// Mirror a real backend: return only the items this query would match —
|
|
31
|
+
// in the block range, part of the selection, and (for non-wildcard events)
|
|
32
|
+
// emitted by an address the partition is querying. Wildcard events are
|
|
33
|
+
// over-fetched regardless of srcAddress, leaving the client-side address
|
|
34
|
+
// filter to gate them exactly as it does for a HyperSync response. Overlapping
|
|
35
|
+
// queries may return the same item more than once; the buffer dedups it.
|
|
36
|
+
let toBlockQueried = switch toBlock {
|
|
37
|
+
| Some(toBlock) => toBlock
|
|
38
|
+
| None => reportedHeight
|
|
39
39
|
}
|
|
40
|
+
let selectionEventIds = Utils.Set.make()
|
|
41
|
+
selection.onEventRegistrations->Array.forEach(reg =>
|
|
42
|
+
selectionEventIds->Utils.Set.add(reg.eventConfig.id)->ignore
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
let parsedQueueItems = items->Array.filter(item => {
|
|
46
|
+
let eventItem = item->Internal.castUnsafeEventItem
|
|
47
|
+
let {blockNumber, onEventRegistration} = eventItem
|
|
48
|
+
if blockNumber < fromBlock || blockNumber > toBlockQueried {
|
|
49
|
+
false
|
|
50
|
+
} else if !(selectionEventIds->Utils.Set.has(onEventRegistration.eventConfig.id)) {
|
|
51
|
+
false
|
|
52
|
+
} else if onEventRegistration.isWildcard {
|
|
53
|
+
true
|
|
54
|
+
} else {
|
|
55
|
+
let sa = eventItem.payload->Internal.getPayloadSrcAddress->Address.toString
|
|
56
|
+
contractNameByAddress->Utils.Dict.dangerouslyGetNonOption(sa)->Option.isSome
|
|
57
|
+
}
|
|
58
|
+
})
|
|
40
59
|
|
|
41
|
-
let reportedHeight = max(endBlock, 1)
|
|
42
60
|
Promise.resolve({
|
|
43
61
|
Source.knownHeight: reportedHeight,
|
|
44
62
|
blockHashes: [],
|
|
45
|
-
parsedQueueItems
|
|
63
|
+
parsedQueueItems,
|
|
46
64
|
// Simulate keeps the transaction and block inline on the payload; no store pages.
|
|
47
65
|
transactionStore: None,
|
|
48
66
|
blockStore: None,
|
|
49
|
-
fromBlockQueried:
|
|
50
|
-
latestFetchedBlockNumber:
|
|
67
|
+
fromBlockQueried: fromBlock,
|
|
68
|
+
latestFetchedBlockNumber: toBlockQueried,
|
|
51
69
|
latestFetchedBlockTimestamp: 0,
|
|
52
70
|
stats: {
|
|
53
71
|
totalTimeElapsed: 0.,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
5
|
|
|
5
6
|
function make(items, endBlock, chain) {
|
|
6
|
-
let
|
|
7
|
-
contents: false
|
|
8
|
-
};
|
|
7
|
+
let reportedHeight = Primitive_int.max(endBlock, 1);
|
|
9
8
|
return {
|
|
10
9
|
name: "SimulateSource",
|
|
11
10
|
sourceFor: "Sync",
|
|
@@ -20,20 +19,38 @@ function make(items, endBlock, chain) {
|
|
|
20
19
|
requestStats: []
|
|
21
20
|
}),
|
|
22
21
|
getHeightOrThrow: () => Promise.resolve({
|
|
23
|
-
height:
|
|
22
|
+
height: reportedHeight,
|
|
24
23
|
requestStats: []
|
|
25
24
|
}),
|
|
26
|
-
getItemsOrThrow: (
|
|
27
|
-
let
|
|
28
|
-
let
|
|
25
|
+
getItemsOrThrow: (fromBlock, toBlock, param, contractNameByAddress, param$1, param$2, selection, param$3, param$4, param$5) => {
|
|
26
|
+
let toBlockQueried = toBlock !== undefined ? toBlock : reportedHeight;
|
|
27
|
+
let selectionEventIds = new Set();
|
|
28
|
+
selection.onEventRegistrations.forEach(reg => {
|
|
29
|
+
selectionEventIds.add(reg.eventConfig.id);
|
|
30
|
+
});
|
|
31
|
+
let parsedQueueItems = items.filter(item => {
|
|
32
|
+
let blockNumber = item.blockNumber;
|
|
33
|
+
if (blockNumber < fromBlock || blockNumber > toBlockQueried) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
let onEventRegistration = item.onEventRegistration;
|
|
37
|
+
if (!selectionEventIds.has(onEventRegistration.eventConfig.id)) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
if (onEventRegistration.isWildcard) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
let sa = item.payload.srcAddress;
|
|
44
|
+
return Stdlib_Option.isSome(contractNameByAddress[sa]);
|
|
45
|
+
});
|
|
29
46
|
return Promise.resolve({
|
|
30
47
|
knownHeight: reportedHeight,
|
|
31
48
|
blockHashes: [],
|
|
32
|
-
parsedQueueItems:
|
|
49
|
+
parsedQueueItems: parsedQueueItems,
|
|
33
50
|
transactionStore: undefined,
|
|
34
51
|
blockStore: undefined,
|
|
35
|
-
fromBlockQueried:
|
|
36
|
-
latestFetchedBlockNumber:
|
|
52
|
+
fromBlockQueried: fromBlock,
|
|
53
|
+
latestFetchedBlockNumber: toBlockQueried,
|
|
37
54
|
latestFetchedBlockTimestamp: 0,
|
|
38
55
|
stats: {
|
|
39
56
|
"total time elapsed (s)": 0
|
|
@@ -285,8 +285,8 @@ let make = (
|
|
|
285
285
|
): t => {
|
|
286
286
|
let name = "SvmHyperSync"
|
|
287
287
|
|
|
288
|
-
// Definitions drive query/decode building;
|
|
289
|
-
//
|
|
288
|
+
// Definitions drive query/decode building; registrations drive routing and
|
|
289
|
+
// are attached directly to decoded runtime items.
|
|
290
290
|
let eventConfigs =
|
|
291
291
|
onEventRegistrations->Array.map(reg =>
|
|
292
292
|
reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
|
|
@@ -488,6 +488,16 @@ let make = (
|
|
|
488
488
|
|
|
489
489
|
switch maybeConfig {
|
|
490
490
|
| None => ()
|
|
491
|
+
// Exclude instructions from failed transactions. HyperSync has no
|
|
492
|
+
// server-side predicate to filter instructions by parent-transaction
|
|
493
|
+
// success (`InstructionSelection` only exposes `is_inner`, and
|
|
494
|
+
// instruction/transaction selections union at block level rather than
|
|
495
|
+
// joining), so we filter client-side on the `isCommitted` flag HyperSync
|
|
496
|
+
// already delivers on every instruction row (a required column, zero extra
|
|
497
|
+
// bandwidth). When HyperSync adds a server-side `is_committed` predicate the
|
|
498
|
+
// query can push this down and the client-side check becomes a redundant
|
|
499
|
+
// safety net.
|
|
500
|
+
| Some(_) if !instr.isCommitted => ()
|
|
491
501
|
| Some(onEventRegistration) =>
|
|
492
502
|
let eventConfig =
|
|
493
503
|
onEventRegistration.eventConfig->(
|
|
@@ -521,7 +531,7 @@ let make = (
|
|
|
521
531
|
parsedQueueItems
|
|
522
532
|
->Array.push(
|
|
523
533
|
Internal.Event({
|
|
524
|
-
onEventRegistration,
|
|
534
|
+
onEventRegistration: (onEventRegistration :> Internal.onEventRegistration),
|
|
525
535
|
chain,
|
|
526
536
|
blockNumber: instr.slot,
|
|
527
537
|
logIndex: synthLogIndex(instr),
|