envio 3.3.0-alpha.0 → 3.3.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/evm.schema.json +10 -0
- package/index.d.ts +45 -25
- package/package.json +7 -7
- package/src/Address.res +5 -2
- package/src/Address.res.mjs +3 -1
- package/src/Api.res +1 -1
- package/src/Api.res.mjs +1 -1
- package/src/Batch.res +0 -6
- package/src/Batch.res.mjs +1 -12
- package/src/BatchProcessing.res +7 -12
- package/src/BatchProcessing.res.mjs +8 -7
- package/src/Bin.res +3 -0
- package/src/Bin.res.mjs +4 -0
- package/src/ChainFetching.res +48 -16
- package/src/ChainFetching.res.mjs +36 -17
- package/src/ChainMetadata.res +1 -11
- package/src/ChainMetadata.res.mjs +1 -10
- package/src/ChainState.res +628 -149
- package/src/ChainState.res.mjs +440 -102
- package/src/ChainState.resi +74 -4
- package/src/Config.res +61 -33
- package/src/Config.res.mjs +50 -10
- package/src/ContractRegisterContext.res +2 -12
- package/src/ContractRegisterContext.res.mjs +3 -5
- package/src/Core.res +14 -3
- package/src/CrossChainState.res +142 -93
- package/src/CrossChainState.res.mjs +88 -60
- package/src/CrossChainState.resi +2 -10
- package/src/Ecosystem.res +5 -6
- package/src/Ecosystem.res.mjs +3 -3
- package/src/Env.res +0 -7
- package/src/Env.res.mjs +0 -6
- package/src/Envio.res +17 -11
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +177 -88
- package/src/EventConfigBuilder.res.mjs +99 -42
- package/src/EventProcessing.res +74 -28
- package/src/EventProcessing.res.mjs +55 -29
- package/src/ExitOnCaughtUp.res +10 -2
- package/src/ExitOnCaughtUp.res.mjs +10 -1
- package/src/FetchState.res +558 -300
- package/src/FetchState.res.mjs +437 -423
- package/src/HandlerLoader.res +8 -104
- package/src/HandlerLoader.res.mjs +2 -81
- package/src/HandlerRegister.res +518 -144
- package/src/HandlerRegister.res.mjs +285 -133
- package/src/HandlerRegister.resi +24 -8
- package/src/IndexerLoop.res +2 -3
- package/src/IndexerLoop.res.mjs +1 -1
- package/src/IndexerState.res +10 -11
- package/src/IndexerState.res.mjs +14 -11
- package/src/IndexerState.resi +2 -5
- package/src/IndexingAddresses.res +108 -0
- package/src/IndexingAddresses.res.mjs +101 -0
- package/src/IndexingAddresses.resi +34 -0
- package/src/Internal.res +155 -46
- package/src/Internal.res.mjs +30 -2
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +6 -6
- package/src/LogSelection.res +102 -165
- package/src/LogSelection.res.mjs +101 -116
- package/src/Main.res +71 -236
- package/src/Main.res.mjs +60 -145
- package/src/Metrics.res +74 -0
- package/src/Metrics.res.mjs +75 -0
- package/src/PgStorage.res +4 -4
- package/src/PgStorage.res.mjs +5 -5
- package/src/Prometheus.res +10 -74
- package/src/Prometheus.res.mjs +124 -186
- package/src/PruneStaleHistory.res +2 -2
- package/src/PruneStaleHistory.res.mjs +3 -3
- package/src/RawEvent.res +7 -2
- package/src/RawEvent.res.mjs +4 -4
- package/src/Rollback.res +3 -3
- package/src/Rollback.res.mjs +4 -4
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateDeadInputTracker.res +85 -0
- package/src/SimulateDeadInputTracker.res.mjs +73 -0
- package/src/SimulateDeadInputTracker.resi +12 -0
- package/src/SimulateItems.res +91 -23
- package/src/SimulateItems.res.mjs +55 -32
- package/src/TestIndexer.res +54 -40
- package/src/TestIndexer.res.mjs +37 -30
- package/src/bindings/Performance.res +7 -0
- package/src/bindings/Performance.res.mjs +21 -0
- package/src/bindings/Performance.resi +7 -0
- package/src/bindings/Viem.res +0 -41
- package/src/bindings/Viem.res.mjs +1 -43
- package/src/sources/BlockStore.res +46 -0
- package/src/sources/BlockStore.res.mjs +24 -0
- package/src/sources/EventRouter.res +36 -33
- package/src/sources/EventRouter.res.mjs +13 -14
- package/src/sources/Evm.res +83 -72
- package/src/sources/Evm.res.mjs +53 -69
- package/src/sources/EvmChain.res +18 -20
- package/src/sources/EvmChain.res.mjs +15 -15
- package/src/sources/EvmRpcClient.res +74 -5
- package/src/sources/EvmRpcClient.res.mjs +13 -4
- package/src/sources/FieldMask.res +39 -0
- package/src/sources/FieldMask.res.mjs +42 -0
- package/src/sources/Fuel.res +9 -6
- package/src/sources/Fuel.res.mjs +5 -10
- package/src/sources/HyperFuelSource.res +46 -50
- package/src/sources/HyperFuelSource.res.mjs +64 -54
- package/src/sources/HyperSync.res +39 -7
- package/src/sources/HyperSync.res.mjs +57 -37
- package/src/sources/HyperSync.resi +12 -2
- package/src/sources/HyperSyncClient.res +22 -111
- package/src/sources/HyperSyncClient.res.mjs +2 -30
- package/src/sources/HyperSyncHeightStream.res +1 -8
- package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
- package/src/sources/HyperSyncSource.res +94 -107
- package/src/sources/HyperSyncSource.res.mjs +82 -86
- package/src/sources/Rpc.res +15 -47
- package/src/sources/Rpc.res.mjs +25 -56
- package/src/sources/RpcSource.res +320 -467
- package/src/sources/RpcSource.res.mjs +268 -385
- package/src/sources/RpcWebSocketHeightStream.res +0 -5
- package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
- package/src/sources/SimulateSource.res +10 -4
- package/src/sources/SimulateSource.res.mjs +16 -6
- package/src/sources/Source.res +34 -6
- package/src/sources/SourceManager.res +86 -27
- package/src/sources/SourceManager.res.mjs +84 -47
- package/src/sources/SourceManager.resi +12 -3
- package/src/sources/Svm.res +31 -16
- package/src/sources/Svm.res.mjs +36 -13
- package/src/sources/SvmHyperSyncClient.res +5 -32
- package/src/sources/SvmHyperSyncSource.res +159 -134
- package/src/sources/SvmHyperSyncSource.res.mjs +164 -129
- package/src/sources/TransactionStore.res +49 -0
- package/src/sources/TransactionStore.res.mjs +30 -0
- package/src/tui/Tui.res +13 -16
- package/src/tui/Tui.res.mjs +12 -14
- package/svm.schema.json +49 -37
- package/src/bindings/Hrtime.res +0 -58
- package/src/bindings/Hrtime.res.mjs +0 -90
- package/src/bindings/Hrtime.resi +0 -30
package/src/Internal.res
CHANGED
|
@@ -58,7 +58,6 @@ type evmTransactionField =
|
|
|
58
58
|
| @as("root") Root
|
|
59
59
|
| @as("status") Status
|
|
60
60
|
| @as("yParity") YParity
|
|
61
|
-
| @as("accessList") AccessList
|
|
62
61
|
| @as("maxFeePerBlobGas") MaxFeePerBlobGas
|
|
63
62
|
| @as("blobVersionedHashes") BlobVersionedHashes
|
|
64
63
|
| @as("type") Type
|
|
@@ -67,6 +66,7 @@ type evmTransactionField =
|
|
|
67
66
|
| @as("l1GasUsed") L1GasUsed
|
|
68
67
|
| @as("l1FeeScalar") L1FeeScalar
|
|
69
68
|
| @as("gasUsedForL1") GasUsedForL1
|
|
69
|
+
| @as("accessList") AccessList
|
|
70
70
|
| @as("authorizationList") AuthorizationList
|
|
71
71
|
|
|
72
72
|
let allEvmBlockFields: array<evmBlockField> = [
|
|
@@ -123,7 +123,6 @@ let allEvmTransactionFields: array<evmTransactionField> = [
|
|
|
123
123
|
Root,
|
|
124
124
|
Status,
|
|
125
125
|
YParity,
|
|
126
|
-
AccessList,
|
|
127
126
|
MaxFeePerBlobGas,
|
|
128
127
|
BlobVersionedHashes,
|
|
129
128
|
Type,
|
|
@@ -132,10 +131,54 @@ let allEvmTransactionFields: array<evmTransactionField> = [
|
|
|
132
131
|
L1GasUsed,
|
|
133
132
|
L1FeeScalar,
|
|
134
133
|
GasUsedForL1,
|
|
134
|
+
AccessList,
|
|
135
135
|
AuthorizationList,
|
|
136
136
|
]
|
|
137
137
|
let evmTransactionFieldSchema = S.enum(allEvmTransactionFields)
|
|
138
138
|
|
|
139
|
+
// SVM transaction fields. Order mirrors the Rust `SvmTxField` ordinals (the bit
|
|
140
|
+
// position in the selection mask) and `Svm.res` `transactionFields`.
|
|
141
|
+
type svmTransactionField =
|
|
142
|
+
| @as("transactionIndex") TransactionIndex
|
|
143
|
+
| @as("signatures") Signatures
|
|
144
|
+
| @as("feePayer") FeePayer
|
|
145
|
+
| @as("success") Success
|
|
146
|
+
| @as("err") Err
|
|
147
|
+
| @as("fee") Fee
|
|
148
|
+
| @as("computeUnitsConsumed") ComputeUnitsConsumed
|
|
149
|
+
| @as("accountKeys") AccountKeys
|
|
150
|
+
| @as("recentBlockhash") RecentBlockhash
|
|
151
|
+
| @as("version") Version
|
|
152
|
+
| @as("tokenBalances") TokenBalances
|
|
153
|
+
|
|
154
|
+
let allSvmTransactionFields: array<svmTransactionField> = [
|
|
155
|
+
TransactionIndex,
|
|
156
|
+
Signatures,
|
|
157
|
+
FeePayer,
|
|
158
|
+
Success,
|
|
159
|
+
Err,
|
|
160
|
+
Fee,
|
|
161
|
+
ComputeUnitsConsumed,
|
|
162
|
+
AccountKeys,
|
|
163
|
+
RecentBlockhash,
|
|
164
|
+
Version,
|
|
165
|
+
TokenBalances,
|
|
166
|
+
]
|
|
167
|
+
let svmTransactionFieldSchema = S.enum(allSvmTransactionFields)
|
|
168
|
+
|
|
169
|
+
// All SVM block fields. `slot`/`time`/`hash` are always included; the rest are
|
|
170
|
+
// selectable via `field_selection.block_fields` (see `allSvmBlockFields`).
|
|
171
|
+
type svmBlockField =
|
|
172
|
+
| @as("slot") Slot
|
|
173
|
+
| @as("time") Time
|
|
174
|
+
| @as("hash") Hash
|
|
175
|
+
| @as("height") Height
|
|
176
|
+
| @as("parentSlot") ParentSlot
|
|
177
|
+
| @as("parentHash") ParentHash
|
|
178
|
+
|
|
179
|
+
let allSvmBlockFields: array<svmBlockField> = [Height, ParentSlot, ParentHash]
|
|
180
|
+
let svmBlockFieldSchema = S.enum(allSvmBlockFields)
|
|
181
|
+
|
|
139
182
|
// Static sets of nullable field names — used by RpcSource and HyperSyncSource to wrap schemas with S.nullable
|
|
140
183
|
let evmNullableBlockFields = Utils.Set.fromArray(
|
|
141
184
|
(
|
|
@@ -265,8 +308,8 @@ type genericEvent<'params, 'block, 'transaction> = {
|
|
|
265
308
|
block: 'block,
|
|
266
309
|
}
|
|
267
310
|
|
|
268
|
-
// Opaque internally — block
|
|
269
|
-
//
|
|
311
|
+
// Opaque internally — the block number needed by the runtime lives on the
|
|
312
|
+
// item instead.
|
|
270
313
|
type event
|
|
271
314
|
|
|
272
315
|
// Opaque payload an item carries. A source builds an ecosystem-specific
|
|
@@ -277,7 +320,15 @@ type event
|
|
|
277
320
|
// modules, not here, and are distinct per ecosystem.
|
|
278
321
|
type eventPayload
|
|
279
322
|
|
|
280
|
-
|
|
323
|
+
// Generic access to the payload's `transaction`, written at batch prep for
|
|
324
|
+
// store-backed ecosystems (HyperSync) and present inline otherwise.
|
|
325
|
+
@get external getPayloadTransaction: eventPayload => Nullable.t<eventTransaction> = "transaction"
|
|
326
|
+
@set external setPayloadTransaction: (eventPayload, eventTransaction) => unit = "transaction"
|
|
327
|
+
|
|
328
|
+
// Generic access to the payload's `block`: written/enriched at batch prep for
|
|
329
|
+
// store-backed ecosystems (EVM/SVM HyperSync) and present inline otherwise.
|
|
330
|
+
@get external getPayloadBlock: eventPayload => Nullable.t<eventBlock> = "block"
|
|
331
|
+
@set external setPayloadBlock: (eventPayload, eventBlock) => unit = "block"
|
|
281
332
|
|
|
282
333
|
type genericLoaderArgs<'event, 'context> = {
|
|
283
334
|
event: 'event,
|
|
@@ -357,31 +408,33 @@ type indexingContract = {
|
|
|
357
408
|
effectiveStartBlock: int,
|
|
358
409
|
}
|
|
359
410
|
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
//
|
|
411
|
+
// Definition of an event/instruction we know how to decode: identity + decode
|
|
412
|
+
// schemas + chain-independent field selection. A pure function of the ABI +
|
|
413
|
+
// config, shared across chains. `private` so it can only be coerced from an
|
|
414
|
+
// ecosystem variant (fields never overwritten), which lets sources cast the
|
|
415
|
+
// base back down to evm/fuel/svm safely.
|
|
364
416
|
type eventConfig = private {
|
|
365
417
|
id: string,
|
|
366
418
|
name: string,
|
|
367
419
|
contractName: string,
|
|
368
|
-
isWildcard: bool,
|
|
369
|
-
// Whether the event has an event filter which uses addresses
|
|
370
|
-
filterByAddresses: bool,
|
|
371
|
-
// Usually always false for wildcard events
|
|
372
|
-
// But might be true for wildcard event with dynamic event filter by addresses
|
|
373
|
-
dependsOnAddresses: bool,
|
|
374
|
-
// Precompiled predicate (EVM only) for events that filter an indexed address
|
|
375
|
-
// param by registered addresses. Given the decoded event and the log's block
|
|
376
|
-
// number, drops an event whose param-address isn't registered at/before that
|
|
377
|
-
// block — the param-level analogue of EventRouter's srcAddress
|
|
378
|
-
// `effectiveStartBlock` check. Absent otherwise.
|
|
379
|
-
clientAddressFilter?: (eventPayload, int, dict<indexingContract>) => bool,
|
|
380
|
-
handler: option<handler>,
|
|
381
|
-
contractRegister: option<contractRegister>,
|
|
382
420
|
paramsRawEventSchema: S.schema<eventParams>,
|
|
383
421
|
simulateParamsSchema: S.schema<eventParams>,
|
|
384
|
-
|
|
422
|
+
// Field names selected for the chain's transaction-store materialisation
|
|
423
|
+
// (camelCase, matching the ecosystem's `transactionFields`). Stored as a
|
|
424
|
+
// string set so the shared mask logic is ecosystem-agnostic; sources recover
|
|
425
|
+
// the typed view where they need it.
|
|
426
|
+
selectedTransactionFields: Utils.Set.t<string>,
|
|
427
|
+
// `selectedTransactionFields` precompiled to the transaction-store selection
|
|
428
|
+
// bitmask (bit per ecosystem field code). Materialisation reads this per item
|
|
429
|
+
// so each transaction decodes only the fields its event selected. `0.` when
|
|
430
|
+
// nothing is selected or the ecosystem carries the transaction inline (Fuel).
|
|
431
|
+
transactionFieldMask: float,
|
|
432
|
+
// Selected block fields precompiled to the block-store selection bitmask (bit
|
|
433
|
+
// per ecosystem field code). `0.` for ecosystems that carry the block fully
|
|
434
|
+
// inline (RPC/Fuel). The EVM selection always includes number/timestamp/hash,
|
|
435
|
+
// so an EVM mask always has their bits set; SVM stamps slot/time/hash inline
|
|
436
|
+
// from the response and its mask is the user's selection alone.
|
|
437
|
+
blockFieldMask: float,
|
|
385
438
|
}
|
|
386
439
|
|
|
387
440
|
type fuelEventKind =
|
|
@@ -406,30 +459,46 @@ type topicSelection = {
|
|
|
406
459
|
topic3: array<EvmTypes.Hex.t>,
|
|
407
460
|
}
|
|
408
461
|
|
|
462
|
+
// A single topic position of a resolved `where`: either static pre-encoded
|
|
463
|
+
// values, or a marker for "the currently registered addresses of this
|
|
464
|
+
// contract", expanded to topic values when a source query is built.
|
|
465
|
+
type topicFilter =
|
|
466
|
+
| Values(array<EvmTypes.Hex.t>)
|
|
467
|
+
| ContractAddresses({contractName: string})
|
|
468
|
+
|
|
469
|
+
type resolvedTopicSelection = {
|
|
470
|
+
topic0: array<EvmTypes.Hex.t>,
|
|
471
|
+
topic1: topicFilter,
|
|
472
|
+
topic2: topicFilter,
|
|
473
|
+
topic3: topicFilter,
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// The registered `where` fully resolved at registration time for one chain.
|
|
477
|
+
// `topicSelections` is in disjunctive normal form (outer array is OR);
|
|
478
|
+
// an empty array means the `where` returned `false` for this chain.
|
|
479
|
+
type resolvedWhere = {
|
|
480
|
+
topicSelections: array<resolvedTopicSelection>,
|
|
481
|
+
startBlock: option<int>,
|
|
482
|
+
}
|
|
483
|
+
|
|
409
484
|
// Per-event, per-invocation arguments passed to a `where` callback. The
|
|
410
485
|
// concrete `chain` shape (which contract key it exposes) is generated per
|
|
411
486
|
// event in user-project codegen — here it's an open record so codegen'd
|
|
412
487
|
// types subtype-coerce into it cleanly.
|
|
413
488
|
type onEventWhereArgs<'chain> = {chain: 'chain}
|
|
414
489
|
|
|
415
|
-
type eventFilters =
|
|
416
|
-
Static(array<topicSelection>) | Dynamic(array<Address.t> => array<topicSelection>)
|
|
417
|
-
|
|
418
490
|
type evmEventConfig = {
|
|
419
491
|
...eventConfig,
|
|
420
|
-
getEventFiltersOrThrow: ChainMap.Chain.t => eventFilters,
|
|
421
492
|
selectedBlockFields: Utils.Set.t<evmBlockField>,
|
|
422
|
-
selectedTransactionFields: Utils.Set.t<evmTransactionField>,
|
|
423
493
|
sighash: string,
|
|
424
494
|
topicCount: int,
|
|
425
495
|
paramsMetadata: array<paramMeta>,
|
|
426
496
|
}
|
|
427
497
|
|
|
428
|
-
// Shared formula for `
|
|
429
|
-
// `EventConfigBuilder.build
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
// there simply pass it through as `false`.
|
|
498
|
+
// Shared formula for a registration's `dependsOnAddresses`. Kept here so the
|
|
499
|
+
// `EventConfigBuilder.build*OnEventRegistration` builders stay in sync. Fuel
|
|
500
|
+
// and SVM events always have `filterByAddresses=false`, so callers there pass
|
|
501
|
+
// it through as `false`.
|
|
433
502
|
let dependsOnAddresses = (~isWildcard, ~filterByAddresses) => !isWildcard || filterByAddresses
|
|
434
503
|
|
|
435
504
|
type evmContractConfig = {
|
|
@@ -448,6 +517,10 @@ type svmAccountFilterGroup = array<svmAccountFilter>
|
|
|
448
517
|
|
|
449
518
|
type svmInstructionEventConfig = {
|
|
450
519
|
...eventConfig,
|
|
520
|
+
/** Block fields selected via `field_selection.block_fields` (`slot` is always
|
|
521
|
+
included and excluded from this set). Drives the block query columns;
|
|
522
|
+
precompiled to `blockFieldMask` for store materialisation. */
|
|
523
|
+
selectedBlockFields: Utils.Set.t<svmBlockField>,
|
|
451
524
|
/** Base58 Solana program id this instruction belongs to. */
|
|
452
525
|
programId: SvmTypes.Pubkey.t,
|
|
453
526
|
/** Hex-encoded discriminator. `None` matches every instruction in the program. */
|
|
@@ -456,9 +529,7 @@ type svmInstructionEventConfig = {
|
|
|
456
529
|
`dN` selector at query time and the dispatch-key precomputation in the
|
|
457
530
|
router. */
|
|
458
531
|
discriminatorByteLen: int,
|
|
459
|
-
includeTransaction: bool,
|
|
460
532
|
includeLogs: bool,
|
|
461
|
-
includeTokenBalances: bool,
|
|
462
533
|
/** Disjunctive normal form: outer array is OR of AND-groups, inner array is
|
|
463
534
|
AND across positions. Empty outer array means "no account filter". */
|
|
464
535
|
accountFilters: array<svmAccountFilterGroup>,
|
|
@@ -476,6 +547,44 @@ type svmInstructionEventConfig = {
|
|
|
476
547
|
definedTypes: JSON.t,
|
|
477
548
|
}
|
|
478
549
|
|
|
550
|
+
// Per-(event, chain) registration produced when user handler code registers an
|
|
551
|
+
// event (`onEvent`) or a dynamic contract registers. References its definition
|
|
552
|
+
// by value as `.eventConfig` and adds the handler binding plus the
|
|
553
|
+
// registration/`where`-derived fetch state. Not `private`: Fuel/SVM
|
|
554
|
+
// registrations add no ecosystem-specific fields (so they're bare aliases that
|
|
555
|
+
// must stay directly constructable), and the evm→base cast in sources is sound
|
|
556
|
+
// by ecosystem homogeneity — an EVM chain only ever holds `evmOnEventRegistration`s.
|
|
557
|
+
type onEventRegistration = {
|
|
558
|
+
eventConfig: eventConfig,
|
|
559
|
+
handler: option<handler>,
|
|
560
|
+
contractRegister: option<contractRegister>,
|
|
561
|
+
isWildcard: bool,
|
|
562
|
+
// Whether the event has an event filter which uses addresses.
|
|
563
|
+
filterByAddresses: bool,
|
|
564
|
+
// Usually always false for wildcard events, but might be true for a wildcard
|
|
565
|
+
// event with a dynamic event filter by addresses.
|
|
566
|
+
dependsOnAddresses: bool,
|
|
567
|
+
// Precompiled predicate for events that filter an indexed address param by
|
|
568
|
+
// registered addresses (see `EventConfigBuilder.buildAddressFilter`); drops a
|
|
569
|
+
// decoded event whose param-address isn't registered at/before the log's
|
|
570
|
+
// block. Absent otherwise.
|
|
571
|
+
clientAddressFilter?: (eventPayload, int, dict<indexingContract>) => bool,
|
|
572
|
+
// Final start block: the contract/chain config value, overridden by a
|
|
573
|
+
// `where.block.number._gte` when the registered `where` supplies one.
|
|
574
|
+
startBlock: option<int>,
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
type evmOnEventRegistration = {
|
|
578
|
+
...onEventRegistration,
|
|
579
|
+
resolvedWhere: resolvedWhere,
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Fuel and SVM registrations add no ecosystem-specific fetch state (their
|
|
583
|
+
// filters are config-derived and live on the definition), so they're bare
|
|
584
|
+
// aliases of the base registration.
|
|
585
|
+
type fuelOnEventRegistration = onEventRegistration
|
|
586
|
+
type svmOnEventRegistration = onEventRegistration
|
|
587
|
+
|
|
479
588
|
type svmProgramConfig = {
|
|
480
589
|
name: string,
|
|
481
590
|
programId: SvmTypes.Pubkey.t,
|
|
@@ -496,12 +605,13 @@ type dcs = array<indexingAddress>
|
|
|
496
605
|
// to make item properly unboxed
|
|
497
606
|
type eventItem = private {
|
|
498
607
|
kind: [#0],
|
|
499
|
-
|
|
500
|
-
timestamp: int,
|
|
608
|
+
onEventRegistration: onEventRegistration,
|
|
501
609
|
chain: ChainMap.Chain.t,
|
|
502
610
|
blockNumber: int,
|
|
503
|
-
blockHash: string,
|
|
504
611
|
logIndex: int,
|
|
612
|
+
// Within-block transaction index — the key into the per-chain transaction
|
|
613
|
+
// store. Unused (0) for ecosystems that carry the transaction inline (Fuel).
|
|
614
|
+
transactionIndex: int,
|
|
505
615
|
payload: eventPayload,
|
|
506
616
|
}
|
|
507
617
|
|
|
@@ -532,7 +642,7 @@ type onBlockArgs = {
|
|
|
532
642
|
context: handlerContext,
|
|
533
643
|
}
|
|
534
644
|
|
|
535
|
-
type
|
|
645
|
+
type onBlockRegistration = {
|
|
536
646
|
// When there are multiple onBlock handlers per chain,
|
|
537
647
|
// we want to use the order they are defined for sorting
|
|
538
648
|
index: int,
|
|
@@ -548,15 +658,14 @@ type onBlockConfig = {
|
|
|
548
658
|
type item =
|
|
549
659
|
| @as(0)
|
|
550
660
|
Event({
|
|
551
|
-
|
|
552
|
-
timestamp: int,
|
|
661
|
+
onEventRegistration: onEventRegistration,
|
|
553
662
|
chain: ChainMap.Chain.t,
|
|
554
663
|
blockNumber: int,
|
|
555
|
-
blockHash: string,
|
|
556
664
|
logIndex: int,
|
|
665
|
+
transactionIndex: int,
|
|
557
666
|
payload: eventPayload,
|
|
558
667
|
})
|
|
559
|
-
| @as(1) Block({
|
|
668
|
+
| @as(1) Block({onBlockRegistration: onBlockRegistration, blockNumber: int, logIndex: int})
|
|
560
669
|
|
|
561
670
|
external castUnsafeEventItem: item => eventItem = "%identity"
|
|
562
671
|
|
|
@@ -568,7 +677,7 @@ external getItemLogIndex: item => int = "logIndex"
|
|
|
568
677
|
let getItemChainId = item =>
|
|
569
678
|
switch item {
|
|
570
679
|
| Event({chain}) => chain->ChainMap.Chain.toChainId
|
|
571
|
-
| Block({
|
|
680
|
+
| Block({onBlockRegistration: {chainId}}) => chainId
|
|
572
681
|
}
|
|
573
682
|
|
|
574
683
|
@get
|
|
@@ -653,7 +762,7 @@ type effect = {
|
|
|
653
762
|
input: S.t<effectInput>,
|
|
654
763
|
// The number of functions that are currently running.
|
|
655
764
|
mutable activeCallsCount: int,
|
|
656
|
-
mutable prevCallStartTimerRef:
|
|
765
|
+
mutable prevCallStartTimerRef: Performance.timeRef,
|
|
657
766
|
rateLimit: option<rateLimitState>,
|
|
658
767
|
}
|
|
659
768
|
let cacheTablePrefix = "envio_effect_"
|
package/src/Internal.res.mjs
CHANGED
|
@@ -60,7 +60,6 @@ let allEvmTransactionFields = [
|
|
|
60
60
|
"root",
|
|
61
61
|
"status",
|
|
62
62
|
"yParity",
|
|
63
|
-
"accessList",
|
|
64
63
|
"maxFeePerBlobGas",
|
|
65
64
|
"blobVersionedHashes",
|
|
66
65
|
"type",
|
|
@@ -69,11 +68,36 @@ let allEvmTransactionFields = [
|
|
|
69
68
|
"l1GasUsed",
|
|
70
69
|
"l1FeeScalar",
|
|
71
70
|
"gasUsedForL1",
|
|
71
|
+
"accessList",
|
|
72
72
|
"authorizationList"
|
|
73
73
|
];
|
|
74
74
|
|
|
75
75
|
let evmTransactionFieldSchema = S$RescriptSchema.$$enum(allEvmTransactionFields);
|
|
76
76
|
|
|
77
|
+
let allSvmTransactionFields = [
|
|
78
|
+
"transactionIndex",
|
|
79
|
+
"signatures",
|
|
80
|
+
"feePayer",
|
|
81
|
+
"success",
|
|
82
|
+
"err",
|
|
83
|
+
"fee",
|
|
84
|
+
"computeUnitsConsumed",
|
|
85
|
+
"accountKeys",
|
|
86
|
+
"recentBlockhash",
|
|
87
|
+
"version",
|
|
88
|
+
"tokenBalances"
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
let svmTransactionFieldSchema = S$RescriptSchema.$$enum(allSvmTransactionFields);
|
|
92
|
+
|
|
93
|
+
let allSvmBlockFields = [
|
|
94
|
+
"height",
|
|
95
|
+
"parentSlot",
|
|
96
|
+
"parentHash"
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
let svmBlockFieldSchema = S$RescriptSchema.$$enum(allSvmBlockFields);
|
|
100
|
+
|
|
77
101
|
let evmNullableBlockFields = new Set([
|
|
78
102
|
"nonce",
|
|
79
103
|
"difficulty",
|
|
@@ -125,7 +149,7 @@ function getItemChainId(item) {
|
|
|
125
149
|
if (item.kind === 0) {
|
|
126
150
|
return item.chain;
|
|
127
151
|
} else {
|
|
128
|
-
return item.
|
|
152
|
+
return item.onBlockRegistration.chainId;
|
|
129
153
|
}
|
|
130
154
|
}
|
|
131
155
|
|
|
@@ -160,6 +184,10 @@ export {
|
|
|
160
184
|
evmBlockFieldSchema,
|
|
161
185
|
allEvmTransactionFields,
|
|
162
186
|
evmTransactionFieldSchema,
|
|
187
|
+
allSvmTransactionFields,
|
|
188
|
+
svmTransactionFieldSchema,
|
|
189
|
+
allSvmBlockFields,
|
|
190
|
+
svmBlockFieldSchema,
|
|
163
191
|
evmNullableBlockFields,
|
|
164
192
|
evmNullableTransactionFields,
|
|
165
193
|
dependsOnAddresses,
|
package/src/LoadLayer.res
CHANGED
|
@@ -85,7 +85,7 @@ let callEffect = (
|
|
|
85
85
|
)
|
|
86
86
|
|
|
87
87
|
if hadActiveCalls {
|
|
88
|
-
let elapsed =
|
|
88
|
+
let elapsed = Performance.secondsBetween(~from=effect.prevCallStartTimerRef, ~to=timerRef)
|
|
89
89
|
if elapsed > 0. {
|
|
90
90
|
Prometheus.EffectCalls.timeCounter->Prometheus.SafeCounter.handleFloat(
|
|
91
91
|
~labels=effectName,
|
|
@@ -113,17 +113,17 @@ let callEffect = (
|
|
|
113
113
|
~labels=effectName,
|
|
114
114
|
~value=effect.activeCallsCount,
|
|
115
115
|
)
|
|
116
|
-
let newTimer =
|
|
116
|
+
let newTimer = Performance.now()
|
|
117
117
|
Prometheus.EffectCalls.timeCounter->Prometheus.SafeCounter.handleFloat(
|
|
118
118
|
~labels=effectName,
|
|
119
|
-
~value=
|
|
119
|
+
~value=Performance.secondsBetween(~from=effect.prevCallStartTimerRef, ~to=newTimer),
|
|
120
120
|
)
|
|
121
121
|
effect.prevCallStartTimerRef = newTimer
|
|
122
122
|
|
|
123
123
|
Prometheus.EffectCalls.totalCallsCount->Prometheus.SafeCounter.increment(~labels=effectName)
|
|
124
124
|
Prometheus.EffectCalls.sumTimeCounter->Prometheus.SafeCounter.handleFloat(
|
|
125
125
|
~labels=effectName,
|
|
126
|
-
~value=timerRef->
|
|
126
|
+
~value=timerRef->Performance.secondsSince,
|
|
127
127
|
)
|
|
128
128
|
})
|
|
129
129
|
}
|
|
@@ -137,7 +137,7 @@ let rec executeWithRateLimit = (
|
|
|
137
137
|
) => {
|
|
138
138
|
let effectName = effect.name
|
|
139
139
|
|
|
140
|
-
let timerRef =
|
|
140
|
+
let timerRef = Performance.now()
|
|
141
141
|
let promises = []
|
|
142
142
|
|
|
143
143
|
switch effect.rateLimit {
|
package/src/LoadLayer.res.mjs
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Table from "./db/Table.res.mjs";
|
|
4
4
|
import * as Utils from "./Utils.res.mjs";
|
|
5
|
-
import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
6
5
|
import * as Logging from "./Logging.res.mjs";
|
|
7
6
|
import * as Ecosystem from "./Ecosystem.res.mjs";
|
|
8
7
|
import * as Prometheus from "./Prometheus.res.mjs";
|
|
9
8
|
import * as LoadManager from "./LoadManager.res.mjs";
|
|
9
|
+
import * as Performance from "./bindings/Performance.res.mjs";
|
|
10
10
|
import * as Persistence from "./Persistence.res.mjs";
|
|
11
11
|
import * as EntityFilter from "./db/EntityFilter.res.mjs";
|
|
12
12
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
@@ -55,7 +55,7 @@ function callEffect(effect, arg, inMemTable, timerRef, onError) {
|
|
|
55
55
|
effect.activeCallsCount = effect.activeCallsCount + 1 | 0;
|
|
56
56
|
Prometheus.SafeGauge.handleInt(Prometheus.EffectCalls.activeCallsCount, effectName, effect.activeCallsCount);
|
|
57
57
|
if (hadActiveCalls) {
|
|
58
|
-
let elapsed =
|
|
58
|
+
let elapsed = Performance.secondsBetween(effect.prevCallStartTimerRef, timerRef);
|
|
59
59
|
if (elapsed > 0) {
|
|
60
60
|
Prometheus.SafeCounter.handleFloat(Prometheus.EffectCalls.timeCounter, effectName, elapsed);
|
|
61
61
|
}
|
|
@@ -64,17 +64,17 @@ function callEffect(effect, arg, inMemTable, timerRef, onError) {
|
|
|
64
64
|
return effect.handler(arg).then(output => InMemoryStore.setEffectOutput(inMemTable, arg.checkpointId, arg.cacheKey, output, arg.context.cache)).catch(exn => onError(arg.cacheKey, exn)).finally(() => {
|
|
65
65
|
effect.activeCallsCount = effect.activeCallsCount - 1 | 0;
|
|
66
66
|
Prometheus.SafeGauge.handleInt(Prometheus.EffectCalls.activeCallsCount, effectName, effect.activeCallsCount);
|
|
67
|
-
let newTimer =
|
|
68
|
-
Prometheus.SafeCounter.handleFloat(Prometheus.EffectCalls.timeCounter, effectName,
|
|
67
|
+
let newTimer = Performance.now();
|
|
68
|
+
Prometheus.SafeCounter.handleFloat(Prometheus.EffectCalls.timeCounter, effectName, Performance.secondsBetween(effect.prevCallStartTimerRef, newTimer));
|
|
69
69
|
effect.prevCallStartTimerRef = newTimer;
|
|
70
70
|
Prometheus.SafeCounter.increment(Prometheus.EffectCalls.totalCallsCount, effectName);
|
|
71
|
-
Prometheus.SafeCounter.handleFloat(Prometheus.EffectCalls.sumTimeCounter, effectName,
|
|
71
|
+
Prometheus.SafeCounter.handleFloat(Prometheus.EffectCalls.sumTimeCounter, effectName, Performance.secondsSince(timerRef));
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function executeWithRateLimit(effect, effectArgs, inMemTable, onError, isFromQueue) {
|
|
76
76
|
let effectName = effect.name;
|
|
77
|
-
let timerRef =
|
|
77
|
+
let timerRef = Performance.now();
|
|
78
78
|
let promises = [];
|
|
79
79
|
let state = effect.rateLimit;
|
|
80
80
|
if (state !== undefined) {
|