envio 3.3.0-alpha.7 → 3.3.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +23 -5
- package/package.json +6 -6
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/ChainFetching.res +21 -10
- package/src/ChainFetching.res.mjs +11 -10
- package/src/ChainState.res +401 -171
- package/src/ChainState.res.mjs +270 -104
- package/src/ChainState.resi +19 -7
- package/src/Config.res +11 -27
- package/src/Config.res.mjs +8 -7
- package/src/Core.res +7 -0
- package/src/CrossChainState.res +82 -82
- package/src/CrossChainState.res.mjs +52 -59
- package/src/CrossChainState.resi +1 -1
- package/src/Ecosystem.res +3 -3
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Envio.res +14 -9
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +117 -69
- package/src/EventConfigBuilder.res.mjs +71 -34
- package/src/EventProcessing.res +19 -15
- package/src/EventProcessing.res.mjs +13 -12
- package/src/FetchState.res +410 -185
- package/src/FetchState.res.mjs +268 -253
- package/src/HandlerLoader.res +8 -113
- package/src/HandlerLoader.res.mjs +2 -88
- package/src/HandlerRegister.res +518 -144
- package/src/HandlerRegister.res.mjs +285 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerState.res +6 -3
- package/src/IndexerState.res.mjs +3 -3
- package/src/IndexerState.resi +1 -1
- package/src/IndexingAddresses.res +10 -7
- package/src/IndexingAddresses.res.mjs +8 -7
- package/src/IndexingAddresses.resi +3 -1
- package/src/Internal.res +104 -39
- package/src/Internal.res.mjs +11 -1
- package/src/LogSelection.res +102 -165
- package/src/LogSelection.res.mjs +101 -116
- package/src/Main.res +49 -164
- package/src/Main.res.mjs +39 -104
- package/src/Metrics.res +43 -2
- package/src/Metrics.res.mjs +39 -3
- package/src/Prometheus.res +0 -35
- package/src/Prometheus.res.mjs +33 -68
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateItems.res +20 -7
- package/src/SimulateItems.res.mjs +7 -11
- package/src/TestIndexer.res +1 -1
- package/src/TestIndexer.res.mjs +1 -1
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +19 -12
- package/src/sources/EventRouter.res.mjs +7 -5
- package/src/sources/Evm.res +58 -5
- package/src/sources/Evm.res.mjs +44 -5
- package/src/sources/EvmChain.res +14 -18
- package/src/sources/EvmChain.res.mjs +12 -13
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +8 -3
- package/src/sources/Fuel.res.mjs +5 -4
- package/src/sources/HyperFuelSource.res +31 -40
- package/src/sources/HyperFuelSource.res.mjs +52 -44
- package/src/sources/HyperSync.res +31 -9
- package/src/sources/HyperSync.res.mjs +47 -31
- package/src/sources/HyperSync.resi +10 -3
- package/src/sources/HyperSyncClient.res +15 -4
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +58 -90
- package/src/sources/HyperSyncSource.res.mjs +57 -66
- package/src/sources/RpcSource.res +118 -120
- package/src/sources/RpcSource.res.mjs +92 -74
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +5 -3
- package/src/sources/SimulateSource.res.mjs +12 -4
- package/src/sources/Source.res +19 -5
- package/src/sources/SourceManager.res +60 -10
- package/src/sources/SourceManager.res.mjs +54 -8
- package/src/sources/SourceManager.resi +10 -0
- package/src/sources/Svm.res +14 -10
- package/src/sources/Svm.res.mjs +23 -6
- package/src/sources/SvmHyperSyncClient.res +5 -6
- package/src/sources/SvmHyperSyncSource.res +82 -41
- package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
- package/src/sources/TransactionStore.res +6 -107
- package/src/sources/TransactionStore.res.mjs +5 -86
- package/svm.schema.json +19 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// The single process-wide mutable state record, stashed on `globalThis` so a
|
|
2
|
+
// duplicate envio module instance — e.g. when the CLI's `bin.mjs` resolves
|
|
3
|
+
// envio from one path but the user's handlers resolve it from
|
|
4
|
+
// `node_modules/envio` — shares one state. Without this, each copy keeps its
|
|
5
|
+
// own module-level state: registration would read an empty registry and the
|
|
6
|
+
// `indexer.chains` getters would silently fall back to static config values.
|
|
7
|
+
//
|
|
8
|
+
// Slots are opaque (`unknown`) so this module stays at the bottom of the
|
|
9
|
+
// dependency graph; each owning module casts its slot to the real type once
|
|
10
|
+
// (`HandlerRegister` for the registration slots, `Main` for the runtime
|
|
11
|
+
// slots, `RollbackCommit` for its callbacks).
|
|
12
|
+
//
|
|
13
|
+
// Version-gated: the slot shapes can evolve between envio versions, so the
|
|
14
|
+
// guard uses strict full-version equality. On mismatch we throw with a
|
|
15
|
+
// deduplication hint instead of silently mixing shapes across builds.
|
|
16
|
+
type t = {
|
|
17
|
+
version: string,
|
|
18
|
+
eventRegistrations: dict<unknown>,
|
|
19
|
+
mutable activeRegistration: option<unknown>,
|
|
20
|
+
preRegistered: array<unknown>,
|
|
21
|
+
rollbackCommitCallbacks: array<unknown>,
|
|
22
|
+
mutable indexerState: option<unknown>,
|
|
23
|
+
mutable persistence: option<unknown>,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Record type with `mutable` so assignment typechecks; ReScript keeps the
|
|
27
|
+
// field name verbatim in the generated JS so the globalThis slot is
|
|
28
|
+
// `__envioGlobal`.
|
|
29
|
+
type globalThis = {mutable __envioGlobal: Nullable.t<t>}
|
|
30
|
+
@val external globalThis: globalThis = "globalThis"
|
|
31
|
+
|
|
32
|
+
let value: t = {
|
|
33
|
+
let version = Utils.EnvioPackage.value.version
|
|
34
|
+
switch globalThis.__envioGlobal->Nullable.toOption {
|
|
35
|
+
| Some(existing) if existing.version === version => existing
|
|
36
|
+
| Some(existing) =>
|
|
37
|
+
JsError.throwWithMessage(
|
|
38
|
+
`Multiple incompatible envio versions loaded in the same process: ${existing.version} and ${version}. Deduplicate the 'envio' dependency in your project.`,
|
|
39
|
+
)
|
|
40
|
+
| None =>
|
|
41
|
+
let fresh = {
|
|
42
|
+
version,
|
|
43
|
+
eventRegistrations: Dict.make(),
|
|
44
|
+
activeRegistration: None,
|
|
45
|
+
preRegistered: [],
|
|
46
|
+
rollbackCommitCallbacks: [],
|
|
47
|
+
indexerState: None,
|
|
48
|
+
persistence: None,
|
|
49
|
+
}
|
|
50
|
+
globalThis.__envioGlobal = Nullable.make(fresh)
|
|
51
|
+
fresh
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Utils from "./Utils.res.mjs";
|
|
4
|
+
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
5
|
+
|
|
6
|
+
let version = Utils.EnvioPackage.value.version;
|
|
7
|
+
|
|
8
|
+
let existing = globalThis.__envioGlobal;
|
|
9
|
+
|
|
10
|
+
let value;
|
|
11
|
+
|
|
12
|
+
if (existing == null) {
|
|
13
|
+
let fresh = {
|
|
14
|
+
version: version,
|
|
15
|
+
eventRegistrations: {},
|
|
16
|
+
activeRegistration: undefined,
|
|
17
|
+
preRegistered: [],
|
|
18
|
+
rollbackCommitCallbacks: [],
|
|
19
|
+
indexerState: undefined,
|
|
20
|
+
persistence: undefined
|
|
21
|
+
};
|
|
22
|
+
globalThis.__envioGlobal = fresh;
|
|
23
|
+
value = fresh;
|
|
24
|
+
} else {
|
|
25
|
+
value = 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.`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
value,
|
|
30
|
+
}
|
|
31
|
+
/* existing Not a pure module */
|
|
@@ -243,9 +243,13 @@ let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) => {
|
|
|
243
243
|
} else {
|
|
244
244
|
switch abiType {
|
|
245
245
|
| "address" =>
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
// Lowercase before encoding so mixed-case (checksummed) user input
|
|
247
|
+
// still matches the lowercase hex topics returned by sources.
|
|
248
|
+
|
|
249
|
+
(
|
|
250
|
+
(value: string) =>
|
|
251
|
+
value->String.toLowerCase->Address.unsafeFromString->TopicFilter.fromAddress
|
|
252
|
+
)->(Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
|
|
249
253
|
|
|
250
254
|
| "bool" =>
|
|
251
255
|
TopicFilter.fromBool->(Utils.magic: (bool => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
|
|
@@ -378,46 +382,12 @@ let buildEvmEventConfig = (
|
|
|
378
382
|
~eventName: string,
|
|
379
383
|
~sighash: string,
|
|
380
384
|
~params: array<paramMeta>,
|
|
381
|
-
~isWildcard: bool,
|
|
382
|
-
~handler: option<Internal.handler>,
|
|
383
|
-
~contractRegister: option<Internal.contractRegister>,
|
|
384
|
-
~eventFilters: option<JSON.t>,
|
|
385
|
-
~probeChainId: int,
|
|
386
|
-
~onEventBlockFilterSchema: S.t<option<unknown>>,
|
|
387
385
|
~blockFields: option<array<Internal.evmBlockField>>=?,
|
|
388
386
|
~transactionFields: option<array<Internal.evmTransactionField>>=?,
|
|
389
|
-
~startBlock: option<int>=?,
|
|
390
387
|
~globalBlockFieldsSet: Utils.Set.t<Internal.evmBlockField>=Utils.Set.make(),
|
|
391
388
|
~globalTransactionFieldsSet: Utils.Set.t<Internal.evmTransactionField>=Utils.Set.make(),
|
|
392
389
|
): Internal.evmEventConfig => {
|
|
393
390
|
let topicCount = params->Array.reduce(1, (acc, p) => p.indexed ? acc + 1 : acc)
|
|
394
|
-
let indexedParams = params->Array.filter(p => p.indexed)
|
|
395
|
-
|
|
396
|
-
let {
|
|
397
|
-
getEventFiltersOrThrow,
|
|
398
|
-
filterByAddresses,
|
|
399
|
-
addressFilterParamGroups,
|
|
400
|
-
startBlock: whereStartBlock,
|
|
401
|
-
} = LogSelection.parseEventFiltersOrThrow(
|
|
402
|
-
~eventFilters,
|
|
403
|
-
~sighash,
|
|
404
|
-
~params=indexedParams->Array.map(p => p.name),
|
|
405
|
-
~contractName,
|
|
406
|
-
~probeChainId,
|
|
407
|
-
~onEventBlockFilterSchema,
|
|
408
|
-
~topic1=?indexedParams->Array.get(0)->Option.map(buildTopicGetter),
|
|
409
|
-
~topic2=?indexedParams->Array.get(1)->Option.map(buildTopicGetter),
|
|
410
|
-
~topic3=?indexedParams->Array.get(2)->Option.map(buildTopicGetter),
|
|
411
|
-
)
|
|
412
|
-
|
|
413
|
-
// `where.block.number._gte` overrides the contract-level startBlock
|
|
414
|
-
// when present. The user opts into this explicitly in handler code so
|
|
415
|
-
// it should win over the `config.yaml` contract `start_block`; absent
|
|
416
|
-
// `where.block`, the caller's contract-level value passes through.
|
|
417
|
-
let resolvedStartBlock = switch whereStartBlock {
|
|
418
|
-
| Some(_) as sb => sb
|
|
419
|
-
| None => startBlock
|
|
420
|
-
}
|
|
421
391
|
|
|
422
392
|
let (selectedBlockFields, selectedTransactionFields) = resolveFieldSelection(
|
|
423
393
|
~blockFields,
|
|
@@ -430,26 +400,75 @@ let buildEvmEventConfig = (
|
|
|
430
400
|
id: sighash ++ "_" ++ topicCount->Int.toString,
|
|
431
401
|
name: eventName,
|
|
432
402
|
contractName,
|
|
433
|
-
isWildcard,
|
|
434
|
-
handler,
|
|
435
|
-
contractRegister,
|
|
436
403
|
paramsRawEventSchema: buildParamsSchema(params),
|
|
437
404
|
simulateParamsSchema: buildSimulateParamsSchema(params),
|
|
438
|
-
getEventFiltersOrThrow,
|
|
439
|
-
filterByAddresses,
|
|
440
|
-
clientAddressFilter: ?buildAddressFilter(addressFilterParamGroups, ~isWildcard),
|
|
441
|
-
dependsOnAddresses: !isWildcard || filterByAddresses,
|
|
442
|
-
startBlock: resolvedStartBlock,
|
|
443
405
|
selectedBlockFields,
|
|
444
406
|
selectedTransactionFields,
|
|
445
407
|
transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
|
|
408
|
+
blockFieldMask: Evm.eventBlockFieldMask(
|
|
409
|
+
selectedBlockFields->(
|
|
410
|
+
Utils.magic: Utils.Set.t<Internal.evmBlockField> => Utils.Set.t<string>
|
|
411
|
+
),
|
|
412
|
+
),
|
|
446
413
|
sighash,
|
|
447
414
|
topicCount,
|
|
448
415
|
paramsMetadata: params,
|
|
449
416
|
}
|
|
450
417
|
}
|
|
451
418
|
|
|
452
|
-
//
|
|
419
|
+
// Enrich an EVM definition into a per-(event,chain) registration: resolve the
|
|
420
|
+
// registered `where` for this chain into `resolvedWhere` + address filters,
|
|
421
|
+
// and override `startBlock` with `where.block._gte`.
|
|
422
|
+
let buildEvmOnEventRegistration = (
|
|
423
|
+
~eventConfig: Internal.evmEventConfig,
|
|
424
|
+
~isWildcard: bool,
|
|
425
|
+
~handler: option<Internal.handler>,
|
|
426
|
+
~contractRegister: option<Internal.contractRegister>,
|
|
427
|
+
~where: option<JSON.t>,
|
|
428
|
+
~chainId: int,
|
|
429
|
+
~onEventBlockFilterSchema: S.t<option<unknown>>,
|
|
430
|
+
~startBlock: option<int>=?,
|
|
431
|
+
): Internal.evmOnEventRegistration => {
|
|
432
|
+
let indexedParams = eventConfig.paramsMetadata->Array.filter(p => p.indexed)
|
|
433
|
+
|
|
434
|
+
let {resolvedWhere, filterByAddresses, addressFilterParamGroups} = LogSelection.parseWhereOrThrow(
|
|
435
|
+
~where,
|
|
436
|
+
~sighash=eventConfig.sighash,
|
|
437
|
+
~params=indexedParams->Array.map(p => p.name),
|
|
438
|
+
~contractName=eventConfig.contractName,
|
|
439
|
+
~chainId,
|
|
440
|
+
~onEventBlockFilterSchema,
|
|
441
|
+
~topic1=?indexedParams->Array.get(0)->Option.map(buildTopicGetter),
|
|
442
|
+
~topic2=?indexedParams->Array.get(1)->Option.map(buildTopicGetter),
|
|
443
|
+
~topic3=?indexedParams->Array.get(2)->Option.map(buildTopicGetter),
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
// `where.block.number._gte` overrides the contract-level startBlock when
|
|
447
|
+
// present (an explicit per-event opt-in that wins over `config.yaml`);
|
|
448
|
+
// otherwise the contract/chain value passes through.
|
|
449
|
+
let resolvedStartBlock = switch resolvedWhere.startBlock {
|
|
450
|
+
| Some(_) as sb => sb
|
|
451
|
+
| None => startBlock
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
{
|
|
455
|
+
eventConfig: (eventConfig :> Internal.eventConfig),
|
|
456
|
+
isWildcard,
|
|
457
|
+
handler,
|
|
458
|
+
contractRegister,
|
|
459
|
+
resolvedWhere,
|
|
460
|
+
filterByAddresses,
|
|
461
|
+
clientAddressFilter: ?buildAddressFilter(addressFilterParamGroups, ~isWildcard),
|
|
462
|
+
dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses),
|
|
463
|
+
startBlock: resolvedStartBlock,
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// ============== Build SVM instruction event config ==============
|
|
468
|
+
|
|
469
|
+
// Always-included block fields (slot, time, hash) are prepended at runtime so
|
|
470
|
+
// they're always present regardless of config.
|
|
471
|
+
let alwaysIncludedSvmBlockFields: array<Internal.svmBlockField> = [Slot, Time, Hash]
|
|
453
472
|
|
|
454
473
|
let buildSvmInstructionEventConfig = (
|
|
455
474
|
~contractName: string,
|
|
@@ -459,15 +478,12 @@ let buildSvmInstructionEventConfig = (
|
|
|
459
478
|
~discriminatorByteLen: int,
|
|
460
479
|
~includeLogs: bool,
|
|
461
480
|
~transactionFields: array<Internal.svmTransactionField>=[],
|
|
481
|
+
~blockFields: array<Internal.svmBlockField>=[],
|
|
462
482
|
~accountFilters: array<Internal.svmAccountFilterGroup>,
|
|
463
483
|
~isInner: option<bool>,
|
|
464
|
-
~isWildcard: bool,
|
|
465
|
-
~handler: option<Internal.handler>,
|
|
466
|
-
~contractRegister: option<Internal.contractRegister>,
|
|
467
484
|
~accounts: array<string>=[],
|
|
468
485
|
~args: JSON.t=JSON.Null,
|
|
469
486
|
~definedTypes: JSON.t=JSON.Null,
|
|
470
|
-
~startBlock: option<int>=?,
|
|
471
487
|
): Internal.svmInstructionEventConfig => {
|
|
472
488
|
let paramsSchema =
|
|
473
489
|
S.json(~validate=false)
|
|
@@ -480,6 +496,12 @@ let buildSvmInstructionEventConfig = (
|
|
|
480
496
|
Utils.Set.fromArray(transactionFields)->(
|
|
481
497
|
Utils.magic: Utils.Set.t<Internal.svmTransactionField> => Utils.Set.t<string>
|
|
482
498
|
)
|
|
499
|
+
let selectedBlockFields = Utils.Set.fromArray(
|
|
500
|
+
Array.concat(alwaysIncludedSvmBlockFields, blockFields),
|
|
501
|
+
)
|
|
502
|
+
let blockFieldMask = Svm.eventBlockFieldMask(
|
|
503
|
+
selectedBlockFields->(Utils.magic: Utils.Set.t<Internal.svmBlockField> => Utils.Set.t<string>),
|
|
504
|
+
)
|
|
483
505
|
{
|
|
484
506
|
id: switch discriminator {
|
|
485
507
|
| Some(d) => d
|
|
@@ -487,21 +509,16 @@ let buildSvmInstructionEventConfig = (
|
|
|
487
509
|
},
|
|
488
510
|
name: instructionName,
|
|
489
511
|
contractName,
|
|
490
|
-
isWildcard,
|
|
491
|
-
handler,
|
|
492
|
-
contractRegister,
|
|
493
512
|
paramsRawEventSchema: paramsSchema,
|
|
494
513
|
simulateParamsSchema: paramsSchema,
|
|
495
|
-
filterByAddresses: false,
|
|
496
|
-
dependsOnAddresses: !isWildcard,
|
|
497
|
-
clientAddressFilter: ?buildAddressFilter([], ~isWildcard, ~srcAddressExpr="event.programId"),
|
|
498
|
-
startBlock,
|
|
499
514
|
programId,
|
|
500
515
|
discriminator,
|
|
501
516
|
discriminatorByteLen,
|
|
502
517
|
includeLogs,
|
|
503
518
|
selectedTransactionFields,
|
|
504
519
|
transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
|
|
520
|
+
selectedBlockFields,
|
|
521
|
+
blockFieldMask,
|
|
505
522
|
accountFilters,
|
|
506
523
|
isInner,
|
|
507
524
|
accounts,
|
|
@@ -510,16 +527,33 @@ let buildSvmInstructionEventConfig = (
|
|
|
510
527
|
}
|
|
511
528
|
}
|
|
512
529
|
|
|
530
|
+
// Enrich an SVM definition into a registration. SVM has no `where`; only the
|
|
531
|
+
// handler binding + wildcard-derived address gate are registration state.
|
|
532
|
+
let buildSvmOnEventRegistration = (
|
|
533
|
+
~eventConfig: Internal.svmInstructionEventConfig,
|
|
534
|
+
~isWildcard: bool,
|
|
535
|
+
~handler: option<Internal.handler>,
|
|
536
|
+
~contractRegister: option<Internal.contractRegister>,
|
|
537
|
+
~startBlock: option<int>=?,
|
|
538
|
+
): Internal.svmOnEventRegistration => {
|
|
539
|
+
eventConfig: (eventConfig :> Internal.eventConfig),
|
|
540
|
+
handler,
|
|
541
|
+
contractRegister,
|
|
542
|
+
isWildcard,
|
|
543
|
+
filterByAddresses: false,
|
|
544
|
+
dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses=false),
|
|
545
|
+
clientAddressFilter: ?buildAddressFilter([], ~isWildcard, ~srcAddressExpr="event.programId"),
|
|
546
|
+
startBlock,
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// ============== Build Fuel event config ==============
|
|
550
|
+
|
|
513
551
|
let buildFuelEventConfig = (
|
|
514
552
|
~contractName: string,
|
|
515
553
|
~eventName: string,
|
|
516
554
|
~kind: string,
|
|
517
555
|
~sighash: string,
|
|
518
556
|
~rawAbi: JSON.t,
|
|
519
|
-
~isWildcard: bool,
|
|
520
|
-
~handler: option<Internal.handler>,
|
|
521
|
-
~contractRegister: option<Internal.contractRegister>,
|
|
522
|
-
~startBlock: option<int>=?,
|
|
523
557
|
): Internal.fuelEventConfig => {
|
|
524
558
|
let fuelKind = switch kind {
|
|
525
559
|
| "logData" =>
|
|
@@ -559,18 +593,32 @@ let buildFuelEventConfig = (
|
|
|
559
593
|
},
|
|
560
594
|
name: eventName,
|
|
561
595
|
contractName,
|
|
562
|
-
isWildcard,
|
|
563
|
-
handler,
|
|
564
|
-
contractRegister,
|
|
565
596
|
paramsRawEventSchema: paramsSchema,
|
|
566
597
|
simulateParamsSchema: paramsSchema,
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
clientAddressFilter: ?buildAddressFilter([], ~isWildcard),
|
|
570
|
-
startBlock,
|
|
571
|
-
// Fuel keeps the transaction inline on the payload; nothing to materialise.
|
|
598
|
+
// Fuel keeps the transaction and block inline on the payload; nothing to
|
|
599
|
+
// materialise.
|
|
572
600
|
selectedTransactionFields: Utils.Set.make(),
|
|
573
601
|
transactionFieldMask: 0.,
|
|
602
|
+
blockFieldMask: 0.,
|
|
574
603
|
kind: fuelKind,
|
|
575
604
|
}
|
|
576
605
|
}
|
|
606
|
+
|
|
607
|
+
// Enrich a Fuel definition into a registration (handler binding +
|
|
608
|
+
// wildcard-derived address gate; Fuel never filters by addresses).
|
|
609
|
+
let buildFuelOnEventRegistration = (
|
|
610
|
+
~eventConfig: Internal.fuelEventConfig,
|
|
611
|
+
~isWildcard: bool,
|
|
612
|
+
~handler: option<Internal.handler>,
|
|
613
|
+
~contractRegister: option<Internal.contractRegister>,
|
|
614
|
+
~startBlock: option<int>=?,
|
|
615
|
+
): Internal.fuelOnEventRegistration => {
|
|
616
|
+
eventConfig: (eventConfig :> Internal.eventConfig),
|
|
617
|
+
handler,
|
|
618
|
+
contractRegister,
|
|
619
|
+
isWildcard,
|
|
620
|
+
filterByAddresses: false,
|
|
621
|
+
dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses=false),
|
|
622
|
+
clientAddressFilter: ?buildAddressFilter([], ~isWildcard),
|
|
623
|
+
startBlock,
|
|
624
|
+
}
|
|
@@ -213,7 +213,7 @@ function getTopicEncoder(abiType) {
|
|
|
213
213
|
}
|
|
214
214
|
switch (abiType) {
|
|
215
215
|
case "address" :
|
|
216
|
-
return TopicFilter.fromAddress;
|
|
216
|
+
return value => TopicFilter.fromAddress(value.toLowerCase());
|
|
217
217
|
case "bool" :
|
|
218
218
|
return TopicFilter.fromBool;
|
|
219
219
|
case "bytes" :
|
|
@@ -280,7 +280,7 @@ function buildAddressFilter(groups, isWildcard, srcAddressExprOpt) {
|
|
|
280
280
|
return Stdlib_Option.map(buildAddressFilterBody(groups, isWildcard, srcAddressExpr), compileAddressFilter);
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
function buildEvmEventConfig(contractName, eventName, sighash, params,
|
|
283
|
+
function buildEvmEventConfig(contractName, eventName, sighash, params, blockFields, transactionFields, globalBlockFieldsSetOpt, globalTransactionFieldsSetOpt) {
|
|
284
284
|
let globalBlockFieldsSet = globalBlockFieldsSetOpt !== undefined ? Primitive_option.valFromOption(globalBlockFieldsSetOpt) : new Set();
|
|
285
285
|
let globalTransactionFieldsSet = globalTransactionFieldsSetOpt !== undefined ? Primitive_option.valFromOption(globalTransactionFieldsSetOpt) : new Set();
|
|
286
286
|
let topicCount = Stdlib_Array.reduce(params, 1, (acc, p) => {
|
|
@@ -290,58 +290,71 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, isWildcar
|
|
|
290
290
|
return acc;
|
|
291
291
|
}
|
|
292
292
|
});
|
|
293
|
-
let
|
|
294
|
-
let
|
|
295
|
-
let
|
|
296
|
-
let filterByAddresses = match.filterByAddresses;
|
|
297
|
-
let resolvedStartBlock = whereStartBlock !== undefined ? whereStartBlock : startBlock;
|
|
298
|
-
let match$1 = resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet);
|
|
299
|
-
let selectedTransactionFields = match$1[1];
|
|
293
|
+
let match = resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet);
|
|
294
|
+
let selectedTransactionFields = match[1];
|
|
295
|
+
let selectedBlockFields = match[0];
|
|
300
296
|
return {
|
|
301
297
|
id: sighash + "_" + topicCount.toString(),
|
|
302
298
|
name: eventName,
|
|
303
299
|
contractName: contractName,
|
|
304
|
-
isWildcard: isWildcard,
|
|
305
|
-
filterByAddresses: filterByAddresses,
|
|
306
|
-
dependsOnAddresses: !isWildcard || filterByAddresses,
|
|
307
|
-
clientAddressFilter: buildAddressFilter(match.addressFilterParamGroups, isWildcard, undefined),
|
|
308
|
-
handler: handler,
|
|
309
|
-
contractRegister: contractRegister,
|
|
310
300
|
paramsRawEventSchema: buildParamsSchema(params),
|
|
311
301
|
simulateParamsSchema: buildSimulateParamsSchema(params),
|
|
312
|
-
startBlock: resolvedStartBlock,
|
|
313
302
|
selectedTransactionFields: selectedTransactionFields,
|
|
314
303
|
transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
|
|
315
|
-
|
|
316
|
-
selectedBlockFields:
|
|
304
|
+
blockFieldMask: Evm.eventBlockFieldMask(selectedBlockFields),
|
|
305
|
+
selectedBlockFields: selectedBlockFields,
|
|
317
306
|
sighash: sighash,
|
|
318
307
|
topicCount: topicCount,
|
|
319
308
|
paramsMetadata: params
|
|
320
309
|
};
|
|
321
310
|
}
|
|
322
311
|
|
|
323
|
-
function
|
|
312
|
+
function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, chainId, onEventBlockFilterSchema, startBlock) {
|
|
313
|
+
let indexedParams = eventConfig.paramsMetadata.filter(p => p.indexed);
|
|
314
|
+
let match = LogSelection.parseWhereOrThrow(where, eventConfig.sighash, indexedParams.map(p => p.name), eventConfig.contractName, chainId, onEventBlockFilterSchema, Stdlib_Option.map(indexedParams[0], buildTopicGetter), Stdlib_Option.map(indexedParams[1], buildTopicGetter), Stdlib_Option.map(indexedParams[2], buildTopicGetter));
|
|
315
|
+
let filterByAddresses = match.filterByAddresses;
|
|
316
|
+
let resolvedWhere = match.resolvedWhere;
|
|
317
|
+
let sb = resolvedWhere.startBlock;
|
|
318
|
+
let resolvedStartBlock = sb !== undefined ? sb : startBlock;
|
|
319
|
+
return {
|
|
320
|
+
eventConfig: eventConfig,
|
|
321
|
+
handler: handler,
|
|
322
|
+
contractRegister: contractRegister,
|
|
323
|
+
isWildcard: isWildcard,
|
|
324
|
+
filterByAddresses: filterByAddresses,
|
|
325
|
+
dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, filterByAddresses),
|
|
326
|
+
clientAddressFilter: buildAddressFilter(match.addressFilterParamGroups, isWildcard, undefined),
|
|
327
|
+
startBlock: resolvedStartBlock,
|
|
328
|
+
resolvedWhere: resolvedWhere
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
let alwaysIncludedSvmBlockFields = [
|
|
333
|
+
"slot",
|
|
334
|
+
"time",
|
|
335
|
+
"hash"
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, discriminatorByteLen, includeLogs, transactionFieldsOpt, blockFieldsOpt, accountFilters, isInner, accountsOpt, argsOpt, definedTypesOpt) {
|
|
324
339
|
let transactionFields = transactionFieldsOpt !== undefined ? transactionFieldsOpt : [];
|
|
340
|
+
let blockFields = blockFieldsOpt !== undefined ? blockFieldsOpt : [];
|
|
325
341
|
let accounts = accountsOpt !== undefined ? accountsOpt : [];
|
|
326
342
|
let args = argsOpt !== undefined ? argsOpt : null;
|
|
327
343
|
let definedTypes = definedTypesOpt !== undefined ? definedTypesOpt : null;
|
|
328
344
|
let paramsSchema = Utils.Schema.coerceToJsonPgType(S$RescriptSchema.json(false));
|
|
329
345
|
let selectedTransactionFields = new Set(transactionFields);
|
|
346
|
+
let selectedBlockFields = new Set(alwaysIncludedSvmBlockFields.concat(blockFields));
|
|
347
|
+
let blockFieldMask = Svm.eventBlockFieldMask(selectedBlockFields);
|
|
330
348
|
return {
|
|
331
349
|
id: discriminator !== undefined ? discriminator : "none",
|
|
332
350
|
name: instructionName,
|
|
333
351
|
contractName: contractName,
|
|
334
|
-
isWildcard: isWildcard,
|
|
335
|
-
filterByAddresses: false,
|
|
336
|
-
dependsOnAddresses: !isWildcard,
|
|
337
|
-
clientAddressFilter: buildAddressFilter([], isWildcard, "event.programId"),
|
|
338
|
-
handler: handler,
|
|
339
|
-
contractRegister: contractRegister,
|
|
340
352
|
paramsRawEventSchema: paramsSchema,
|
|
341
353
|
simulateParamsSchema: paramsSchema,
|
|
342
|
-
startBlock: startBlock,
|
|
343
354
|
selectedTransactionFields: selectedTransactionFields,
|
|
344
355
|
transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
|
|
356
|
+
blockFieldMask: blockFieldMask,
|
|
357
|
+
selectedBlockFields: selectedBlockFields,
|
|
345
358
|
programId: programId,
|
|
346
359
|
discriminator: discriminator,
|
|
347
360
|
discriminatorByteLen: discriminatorByteLen,
|
|
@@ -354,7 +367,20 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
|
|
|
354
367
|
};
|
|
355
368
|
}
|
|
356
369
|
|
|
357
|
-
function
|
|
370
|
+
function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
|
|
371
|
+
return {
|
|
372
|
+
eventConfig: eventConfig,
|
|
373
|
+
handler: handler,
|
|
374
|
+
contractRegister: contractRegister,
|
|
375
|
+
isWildcard: isWildcard,
|
|
376
|
+
filterByAddresses: false,
|
|
377
|
+
dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
|
|
378
|
+
clientAddressFilter: buildAddressFilter([], isWildcard, "event.programId"),
|
|
379
|
+
startBlock: startBlock
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
|
|
358
384
|
let fuelKind;
|
|
359
385
|
switch (kind) {
|
|
360
386
|
case "burn" :
|
|
@@ -401,21 +427,28 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi, is
|
|
|
401
427
|
id: tmp,
|
|
402
428
|
name: eventName,
|
|
403
429
|
contractName: contractName,
|
|
404
|
-
isWildcard: isWildcard,
|
|
405
|
-
filterByAddresses: false,
|
|
406
|
-
dependsOnAddresses: !isWildcard,
|
|
407
|
-
clientAddressFilter: buildAddressFilter([], isWildcard, undefined),
|
|
408
|
-
handler: handler,
|
|
409
|
-
contractRegister: contractRegister,
|
|
410
430
|
paramsRawEventSchema: paramsSchema,
|
|
411
431
|
simulateParamsSchema: paramsSchema,
|
|
412
|
-
startBlock: startBlock,
|
|
413
432
|
selectedTransactionFields: new Set(),
|
|
414
433
|
transactionFieldMask: 0,
|
|
434
|
+
blockFieldMask: 0,
|
|
415
435
|
kind: fuelKind
|
|
416
436
|
};
|
|
417
437
|
}
|
|
418
438
|
|
|
439
|
+
function buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
|
|
440
|
+
return {
|
|
441
|
+
eventConfig: eventConfig,
|
|
442
|
+
handler: handler,
|
|
443
|
+
contractRegister: contractRegister,
|
|
444
|
+
isWildcard: isWildcard,
|
|
445
|
+
filterByAddresses: false,
|
|
446
|
+
dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
|
|
447
|
+
clientAddressFilter: buildAddressFilter([], isWildcard, undefined),
|
|
448
|
+
startBlock: startBlock
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
419
452
|
export {
|
|
420
453
|
paramMetaSchema,
|
|
421
454
|
normalizeOrThrow,
|
|
@@ -435,7 +468,11 @@ export {
|
|
|
435
468
|
buildAddressFilterBody,
|
|
436
469
|
buildAddressFilter,
|
|
437
470
|
buildEvmEventConfig,
|
|
471
|
+
buildEvmOnEventRegistration,
|
|
472
|
+
alwaysIncludedSvmBlockFields,
|
|
438
473
|
buildSvmInstructionEventConfig,
|
|
474
|
+
buildSvmOnEventRegistration,
|
|
439
475
|
buildFuelEventConfig,
|
|
476
|
+
buildFuelOnEventRegistration,
|
|
440
477
|
}
|
|
441
478
|
/* paramMetaSchema Not a pure module */
|
package/src/EventProcessing.res
CHANGED
|
@@ -74,8 +74,8 @@ let runEventHandlerOrThrow = async (
|
|
|
74
74
|
}
|
|
75
75
|
let handlerDuration = timeBeforeHandler->Performance.secondsSince
|
|
76
76
|
Prometheus.ProcessingHandler.increment(
|
|
77
|
-
~contract=eventItem.eventConfig.contractName,
|
|
78
|
-
~event=eventItem.eventConfig.name,
|
|
77
|
+
~contract=eventItem.onEventRegistration.eventConfig.contractName,
|
|
78
|
+
~event=eventItem.onEventRegistration.eventConfig.name,
|
|
79
79
|
~duration=handlerDuration,
|
|
80
80
|
)
|
|
81
81
|
}
|
|
@@ -90,7 +90,7 @@ let runHandlerOrThrow = async (
|
|
|
90
90
|
~chains: Internal.chains,
|
|
91
91
|
) => {
|
|
92
92
|
switch item {
|
|
93
|
-
| Block({
|
|
93
|
+
| Block({onBlockRegistration: {handler}, blockNumber}) =>
|
|
94
94
|
try {
|
|
95
95
|
let contextParams: UserContext.contextParams = {
|
|
96
96
|
item,
|
|
@@ -121,8 +121,8 @@ let runHandlerOrThrow = async (
|
|
|
121
121
|
}),
|
|
122
122
|
)
|
|
123
123
|
}
|
|
124
|
-
| Event({
|
|
125
|
-
switch
|
|
124
|
+
| Event({onEventRegistration}) =>
|
|
125
|
+
switch onEventRegistration.handler {
|
|
126
126
|
| Some(handler) =>
|
|
127
127
|
await item->runEventHandlerOrThrow(
|
|
128
128
|
~handler,
|
|
@@ -161,7 +161,7 @@ let preloadBatchOrThrow = async (
|
|
|
161
161
|
for idx in 0 to checkpointEventsProcessed - 1 {
|
|
162
162
|
let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
|
|
163
163
|
switch item {
|
|
164
|
-
| Event({
|
|
164
|
+
| Event({onEventRegistration: {handler, eventConfig: {contractName, name: eventName}}}) =>
|
|
165
165
|
switch handler {
|
|
166
166
|
| None => ()
|
|
167
167
|
| Some(handler) =>
|
|
@@ -200,7 +200,7 @@ let preloadBatchOrThrow = async (
|
|
|
200
200
|
| _ => ()
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
| Block({
|
|
203
|
+
| Block({onBlockRegistration: {handler}, blockNumber}) =>
|
|
204
204
|
try {
|
|
205
205
|
promises->Array.push(
|
|
206
206
|
handler({
|
|
@@ -289,15 +289,19 @@ type logPartitionInfo = {
|
|
|
289
289
|
lastItemBlockNumber?: int,
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
-
// Off the hot path: bulk-materialise the selected transaction
|
|
293
|
-
// batch's store-backed (HyperSync) items and write them onto the
|
|
294
|
-
// handlers read plain objects. A batch can span chains, each with
|
|
295
|
-
// and field
|
|
296
|
-
let
|
|
292
|
+
// Off the hot path: bulk-materialise the selected transaction and block fields
|
|
293
|
+
// for the batch's store-backed (HyperSync) items and write them onto the
|
|
294
|
+
// payloads, so handlers read plain objects. A batch can span chains, each with
|
|
295
|
+
// its own stores and field masks, so group items by chain before materialising.
|
|
296
|
+
let materializeBatchEvents = async (
|
|
297
|
+
batch: Batch.t,
|
|
298
|
+
~chainStates: dict<ChainState.t>,
|
|
299
|
+
~ecosystem,
|
|
300
|
+
) => {
|
|
297
301
|
switch chainStates->Dict.valuesToArray {
|
|
298
302
|
// Single-chain indexers (the common case): every item belongs to the one
|
|
299
303
|
// chain, so skip the per-chain grouping and its allocations.
|
|
300
|
-
| [cs] => await cs->ChainState.materializeBatchItems(~items=batch.items)
|
|
304
|
+
| [cs] => await cs->ChainState.materializeBatchItems(~items=batch.items, ~ecosystem)
|
|
301
305
|
| _ =>
|
|
302
306
|
let itemsByChain: dict<array<Internal.item>> = Dict.make()
|
|
303
307
|
batch.items->Array.forEach(item => {
|
|
@@ -312,7 +316,7 @@ let materializeBatchTransactions = async (batch: Batch.t, ~chainStates: dict<Cha
|
|
|
312
316
|
->Dict.toArray
|
|
313
317
|
->Array.map(async ((chainId, items)) => {
|
|
314
318
|
let cs = chainStates->Dict.getUnsafe(chainId)
|
|
315
|
-
await cs->ChainState.materializeBatchItems(~items)
|
|
319
|
+
await cs->ChainState.materializeBatchItems(~items, ~ecosystem)
|
|
316
320
|
})
|
|
317
321
|
->Promise.all
|
|
318
322
|
}
|
|
@@ -348,7 +352,7 @@ let processEventBatch = async (
|
|
|
348
352
|
if batch.items->Utils.Array.notEmpty {
|
|
349
353
|
// Materialise store-backed transactions onto payloads before any handler
|
|
350
354
|
// (preload or execute) reads them.
|
|
351
|
-
await
|
|
355
|
+
await materializeBatchEvents(batch, ~chainStates, ~ecosystem=config.ecosystem.name)
|
|
352
356
|
await batch->preloadBatchOrThrow(~loadManager, ~persistence, ~indexerState, ~chains, ~config)
|
|
353
357
|
}
|
|
354
358
|
|