envio 3.6.1 → 3.7.0-subgraph
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 +197 -9
- package/package.json +6 -6
- package/src/Batch.res +64 -25
- package/src/Batch.res.mjs +69 -46
- package/src/ChainFetching.res +13 -17
- package/src/ChainFetching.res.mjs +9 -14
- package/src/ChainState.res +160 -119
- package/src/ChainState.res.mjs +75 -46
- package/src/ChainState.resi +15 -12
- package/src/Config.res +18 -2
- package/src/Config.res.mjs +9 -6
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +11 -0
- package/src/Ecosystem.res +0 -1
- package/src/Envio.res +16 -3
- package/src/EventConfigBuilder.res +155 -40
- package/src/EventConfigBuilder.res.mjs +76 -24
- package/src/EventProcessing.res +10 -14
- package/src/EventProcessing.res.mjs +12 -10
- package/src/EventUtils.res +3 -47
- package/src/FetchState.res +124 -104
- package/src/FetchState.res.mjs +116 -100
- package/src/HandlerLoader.res +20 -8
- package/src/HandlerLoader.res.mjs +11 -2
- package/src/HandlerRegister.res +108 -2
- package/src/HandlerRegister.res.mjs +59 -10
- package/src/HandlerRegister.resi +4 -0
- package/src/InMemoryStore.res +1 -6
- package/src/InMemoryStore.res.mjs +1 -3
- package/src/Internal.res +84 -24
- package/src/Internal.res.mjs +33 -2
- package/src/LazyLoader.res +12 -11
- package/src/LazyLoader.res.mjs +13 -7
- package/src/Main.res +22 -9
- package/src/Main.res.mjs +18 -5
- package/src/MemoryStorage.res +756 -0
- package/src/MemoryStorage.res.mjs +623 -0
- package/src/Persistence.res +4 -2
- package/src/PgStorage.res +24 -8
- package/src/PgStorage.res.mjs +15 -12
- package/src/ReorgDetection.res +0 -222
- package/src/ReorgDetection.res.mjs +0 -163
- package/src/Rollback.res +14 -15
- package/src/Rollback.res.mjs +4 -5
- package/src/SimulateItems.res +2 -2
- package/src/UserContext.res +358 -51
- package/src/UserContext.res.mjs +271 -35
- package/src/Utils.res +3 -0
- package/src/bindings/ClickHouse.res +16 -11
- package/src/bindings/ClickHouse.res.mjs +10 -10
- package/src/bindings/Vitest.res +1 -1
- package/src/sources/BlockStore.res +115 -5
- package/src/sources/BlockStore.res.mjs +25 -0
- package/src/sources/Evm.res +0 -1
- package/src/sources/Evm.res.mjs +0 -1
- package/src/sources/EvmHyperSyncSource.res +19 -84
- package/src/sources/EvmHyperSyncSource.res.mjs +24 -60
- package/src/sources/Fuel.res +24 -4
- package/src/sources/Fuel.res.mjs +23 -3
- package/src/sources/FuelHyperSync.res +8 -3
- package/src/sources/FuelHyperSync.res.mjs +5 -4
- package/src/sources/FuelHyperSync.resi +3 -1
- package/src/sources/FuelHyperSyncClient.res +7 -10
- package/src/sources/FuelHyperSyncSource.res +18 -45
- package/src/sources/FuelHyperSyncSource.res.mjs +18 -35
- package/src/sources/HyperSync.res +49 -229
- package/src/sources/HyperSync.res.mjs +74 -191
- package/src/sources/HyperSync.resi +11 -35
- package/src/sources/HyperSyncClient.res +9 -79
- package/src/sources/HyperSyncClient.res.mjs +2 -6
- package/src/sources/RequestStat.res +5 -0
- package/src/sources/RequestStat.res.mjs +2 -0
- package/src/sources/RpcSource.res +149 -43
- package/src/sources/RpcSource.res.mjs +104 -41
- package/src/sources/SimulateSource.res +8 -5
- package/src/sources/SimulateSource.res.mjs +6 -6
- package/src/sources/Source.res +89 -16
- package/src/sources/Source.res.mjs +50 -1
- package/src/sources/SourceManager.res +255 -50
- package/src/sources/SourceManager.res.mjs +149 -55
- package/src/sources/SourceManager.resi +2 -6
- package/src/sources/Svm.res +0 -7
- package/src/sources/Svm.res.mjs +0 -8
- package/src/sources/SvmHyperSyncClient.res +21 -16
- package/src/sources/SvmHyperSyncClient.res.mjs +3 -4
- package/src/sources/SvmHyperSyncSource.res +25 -117
- package/src/sources/SvmHyperSyncSource.res.mjs +8 -121
- package/src/subgraph/blocks.ts +176 -0
- package/src/subgraph/calls.ts +217 -0
- package/src/subgraph/conformance.ts +99 -0
- package/src/subgraph/division.ts +110 -0
- package/src/subgraph/errors.ts +90 -0
- package/src/subgraph/graph-ts-types/VERSION +2 -0
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
- package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
- package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
- package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
- package/src/subgraph/graph-ts-types/index.d.ts +102 -0
- package/src/subgraph/graph-ts.ts +1871 -0
- package/src/subgraph/hosts.ts +148 -0
- package/src/subgraph/runtime.ts +845 -0
- package/src/subgraph/scope.ts +63 -0
- package/svm.schema.json +3 -2
|
@@ -236,8 +236,8 @@ let buildSimulateParamsSchema = (params: array<paramMeta>): S.t<Internal.eventPa
|
|
|
236
236
|
|
|
237
237
|
// ============== Build topic filter getters ==============
|
|
238
238
|
|
|
239
|
-
let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) =>
|
|
240
|
-
Core.getAddon().encodeIndexedTopic(~abiType, ~value)
|
|
239
|
+
let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) =>
|
|
240
|
+
value => Core.getAddon().encodeIndexedTopic(~abiType, ~value)
|
|
241
241
|
|
|
242
242
|
let buildTopicGetter = (p: paramMeta) => {
|
|
243
243
|
let encoder = getTopicEncoder(p.abiType)
|
|
@@ -247,6 +247,7 @@ let buildTopicGetter = (p: paramMeta) => {
|
|
|
247
247
|
->Utils.Dict.dangerouslyGetNonOption(p.name)
|
|
248
248
|
->Option.mapOr([], topicFilters => {
|
|
249
249
|
let raw = topicFilters->(Utils.magic: JSON.t => unknown)
|
|
250
|
+
|
|
250
251
|
// A tuple filter value is itself an array, so a directly-passed tuple is
|
|
251
252
|
// indistinguishable from an OR-list by shape alone. A single tuple is
|
|
252
253
|
// the common case, so try it first; when the value doesn't ABI-encode as
|
|
@@ -282,13 +283,128 @@ let resolveFieldSelection = (
|
|
|
282
283
|
| Some(fields) => Utils.Set.fromArray(fields)
|
|
283
284
|
| None => globalTransactionFieldsSet
|
|
284
285
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
selectedTransactionFields->(
|
|
286
|
+
Internal.makeFieldSelection(
|
|
287
|
+
~blockFields=selectedBlockFields->(
|
|
288
|
+
Utils.magic: Utils.Set.t<Internal.evmBlockField> => Utils.Set.t<string>
|
|
289
|
+
),
|
|
290
|
+
~transactionFields=selectedTransactionFields->(
|
|
290
291
|
Utils.magic: Utils.Set.t<Internal.evmTransactionField> => Utils.Set.t<string>
|
|
291
292
|
),
|
|
293
|
+
~blockMaskFn=Evm.eventBlockFieldMask,
|
|
294
|
+
~transactionMaskFn=Evm.eventTransactionFieldMask,
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// `block.number` is the item's own key, so an inline selection carries it
|
|
299
|
+
// whether or not the handler listed it. Nothing else is added: dropping
|
|
300
|
+
// `timestamp`/`hash` is the point of naming fields inline, and the two things
|
|
301
|
+
// that read them off the payload cope — the progress-latency metric
|
|
302
|
+
// (`ChainState.applyBatchProgress`) skips a batch whose last block has no
|
|
303
|
+
// timestamp, and `raw_events` selects them back below.
|
|
304
|
+
let internalBlockFields = ["number"]
|
|
305
|
+
|
|
306
|
+
// `toRawEvent` reads `block.hash`/`block.timestamp` for the `raw_events` row's
|
|
307
|
+
// own columns, which are not nullable. They stay out of the row's stored
|
|
308
|
+
// `block_fields` (`Evm.cleanUpRawEventFieldsInPlace` strips number/timestamp/
|
|
309
|
+
// hash from it), so the column still holds exactly what the registration
|
|
310
|
+
// selected.
|
|
311
|
+
let rawEventBlockFields = ["hash", "timestamp"]
|
|
312
|
+
|
|
313
|
+
let selectionKinds = ["block", "transaction"]
|
|
314
|
+
|
|
315
|
+
// A handler written in plain JS gets no type error for a `blocks`/`transactions`
|
|
316
|
+
// typo, and an unrecognised key would read as an empty selection — silently
|
|
317
|
+
// dropping every field `config.yaml` selected. Rejected here so the option is
|
|
318
|
+
// held to the same shape whether or not the project type-checks it.
|
|
319
|
+
let validateFieldsShapeOrThrow = (fields: Internal.evmFieldsSelection, ~registration: string) => {
|
|
320
|
+
let raw = fields->(Utils.magic: Internal.evmFieldsSelection => unknown)
|
|
321
|
+
if typeof(raw) !== #object || raw === %raw(`null`) || Array.isArray(raw) {
|
|
322
|
+
JsError.throwWithMessage(
|
|
323
|
+
`The fields option of ${registration} must be an object of block and transaction field names.`,
|
|
324
|
+
)
|
|
325
|
+
}
|
|
326
|
+
raw
|
|
327
|
+
->(Utils.magic: unknown => dict<unknown>)
|
|
328
|
+
->Dict.keysToArray
|
|
329
|
+
->Array.forEach(key =>
|
|
330
|
+
if !(selectionKinds->Array.includes(key)) {
|
|
331
|
+
JsError.throwWithMessage(
|
|
332
|
+
`Invalid "${key}" key in the fields option of ${registration}. Valid keys: ${selectionKinds->Array.joinUnsafe(
|
|
333
|
+
", ",
|
|
334
|
+
)}.`,
|
|
335
|
+
)
|
|
336
|
+
}
|
|
337
|
+
)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
let validBlockFields = Utils.Set.fromArray(Evm.blockFields)
|
|
341
|
+
let validTransactionFields = Utils.Set.fromArray(Evm.transactionFields)
|
|
342
|
+
|
|
343
|
+
let parseFieldsOrThrow = (
|
|
344
|
+
fields: option<array<string>>,
|
|
345
|
+
~valid: Utils.Set.t<string>,
|
|
346
|
+
~kind: string,
|
|
347
|
+
~registration: string,
|
|
348
|
+
) => {
|
|
349
|
+
let seen = Utils.Set.make()
|
|
350
|
+
let fields = switch fields {
|
|
351
|
+
| None => []
|
|
352
|
+
| Some(fields) if !Array.isArray(fields) =>
|
|
353
|
+
JsError.throwWithMessage(
|
|
354
|
+
`The fields.${kind} option of ${registration} must be an array of field names.`,
|
|
355
|
+
)
|
|
356
|
+
| Some(fields) => fields
|
|
357
|
+
}
|
|
358
|
+
fields->Array.forEach(name => {
|
|
359
|
+
if !(valid->Utils.Set.has(name)) {
|
|
360
|
+
JsError.throwWithMessage(
|
|
361
|
+
`Invalid "${name}" field in the fields.${kind} option of ${registration}. Valid ${kind} fields: ${valid
|
|
362
|
+
->Utils.Set.toArray
|
|
363
|
+
->Array.joinUnsafe(", ")}.`,
|
|
364
|
+
)
|
|
365
|
+
}
|
|
366
|
+
if seen->Utils.Set.has(name) {
|
|
367
|
+
JsError.throwWithMessage(
|
|
368
|
+
`Duplicate "${name}" field in the fields.${kind} option of ${registration}.`,
|
|
369
|
+
)
|
|
370
|
+
}
|
|
371
|
+
seen->Utils.Set.add(name)->ignore
|
|
372
|
+
})
|
|
373
|
+
seen
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Resolve an inline `fields` option into a selection. Depends only on the
|
|
377
|
+
// option itself (the names are for error messages), never on the chain, so one
|
|
378
|
+
// `onEvent` call resolves once and shares the result across every chain.
|
|
379
|
+
let resolveInlineFieldSelection = (
|
|
380
|
+
fields: Internal.evmFieldsSelection,
|
|
381
|
+
~contractName: string,
|
|
382
|
+
~eventName: string,
|
|
383
|
+
~enableRawEvents: bool,
|
|
384
|
+
): Internal.fieldSelection => {
|
|
385
|
+
let registration = `the "${eventName}" event registration on contract "${contractName}"`
|
|
386
|
+
validateFieldsShapeOrThrow(fields, ~registration)
|
|
387
|
+
let blockFields = parseFieldsOrThrow(
|
|
388
|
+
fields.block,
|
|
389
|
+
~valid=validBlockFields,
|
|
390
|
+
~kind="block",
|
|
391
|
+
~registration,
|
|
392
|
+
)
|
|
393
|
+
let transactionFields = parseFieldsOrThrow(
|
|
394
|
+
fields.transaction,
|
|
395
|
+
~valid=validTransactionFields,
|
|
396
|
+
~kind="transaction",
|
|
397
|
+
~registration,
|
|
398
|
+
)
|
|
399
|
+
blockFields->Utils.Set.addMany(internalBlockFields)
|
|
400
|
+
if enableRawEvents {
|
|
401
|
+
blockFields->Utils.Set.addMany(rawEventBlockFields)
|
|
402
|
+
}
|
|
403
|
+
Internal.makeFieldSelection(
|
|
404
|
+
~blockFields,
|
|
405
|
+
~transactionFields,
|
|
406
|
+
~blockMaskFn=Evm.eventBlockFieldMask,
|
|
407
|
+
~transactionMaskFn=Evm.eventTransactionFieldMask,
|
|
292
408
|
)
|
|
293
409
|
}
|
|
294
410
|
|
|
@@ -306,26 +422,17 @@ let buildEvmEventConfig = (
|
|
|
306
422
|
): Internal.evmEventConfig => {
|
|
307
423
|
let topicCount = params->Array.reduce(1, (acc, p) => p.indexed ? acc + 1 : acc)
|
|
308
424
|
|
|
309
|
-
let (selectedBlockFields, selectedTransactionFields) = resolveFieldSelection(
|
|
310
|
-
~blockFields,
|
|
311
|
-
~transactionFields,
|
|
312
|
-
~globalBlockFieldsSet,
|
|
313
|
-
~globalTransactionFieldsSet,
|
|
314
|
-
)
|
|
315
|
-
|
|
316
425
|
{
|
|
317
426
|
id: sighash ++ "_" ++ topicCount->Int.toString,
|
|
318
427
|
name: eventName,
|
|
319
428
|
contractName,
|
|
320
429
|
paramsRawEventSchema: buildParamsSchema(params),
|
|
321
430
|
simulateParamsSchema: buildSimulateParamsSchema(params),
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
Utils.magic: Utils.Set.t<Internal.evmBlockField> => Utils.Set.t<string>
|
|
328
|
-
),
|
|
431
|
+
fieldSelection: resolveFieldSelection(
|
|
432
|
+
~blockFields,
|
|
433
|
+
~transactionFields,
|
|
434
|
+
~globalBlockFieldsSet,
|
|
435
|
+
~globalTransactionFieldsSet,
|
|
329
436
|
),
|
|
330
437
|
sighash,
|
|
331
438
|
topicCount,
|
|
@@ -344,6 +451,9 @@ let buildEvmOnEventRegistration = (
|
|
|
344
451
|
~where: option<JSON.t>,
|
|
345
452
|
~chainId: ChainId.t,
|
|
346
453
|
~onEventBlockFilterSchema: S.t<option<unknown>>,
|
|
454
|
+
// The registration's inline selection, already resolved; absent when it named
|
|
455
|
+
// no fields and takes the event config's.
|
|
456
|
+
~fieldSelection: option<Internal.fieldSelection>=?,
|
|
347
457
|
~startBlock: option<int>=?,
|
|
348
458
|
): Internal.evmOnEventRegistration => {
|
|
349
459
|
let indexedParams = eventConfig.paramsMetadata->Array.filter(p => p.indexed)
|
|
@@ -379,6 +489,10 @@ let buildEvmOnEventRegistration = (
|
|
|
379
489
|
addressFilterParamGroups,
|
|
380
490
|
dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses),
|
|
381
491
|
startBlock: resolvedStartBlock,
|
|
492
|
+
fieldSelection: switch fieldSelection {
|
|
493
|
+
| Some(fieldSelection) => fieldSelection
|
|
494
|
+
| None => eventConfig.fieldSelection
|
|
495
|
+
},
|
|
382
496
|
}
|
|
383
497
|
}
|
|
384
498
|
|
|
@@ -408,17 +522,15 @@ let buildSvmInstructionEventConfig = (
|
|
|
408
522
|
->Utils.Schema.coerceToJsonPgType
|
|
409
523
|
->(Utils.magic: S.t<JSON.t> => S.t<Internal.eventParams>)
|
|
410
524
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
525
|
+
let fieldSelection = Internal.makeFieldSelection(
|
|
526
|
+
~blockFields=Utils.Set.fromArray(Array.concat(alwaysIncludedSvmBlockFields, blockFields))->(
|
|
527
|
+
Utils.magic: Utils.Set.t<Internal.svmBlockField> => Utils.Set.t<string>
|
|
528
|
+
),
|
|
529
|
+
~transactionFields=Utils.Set.fromArray(transactionFields)->(
|
|
415
530
|
Utils.magic: Utils.Set.t<Internal.svmTransactionField> => Utils.Set.t<string>
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
)
|
|
420
|
-
let blockFieldMask = Svm.eventBlockFieldMask(
|
|
421
|
-
selectedBlockFields->(Utils.magic: Utils.Set.t<Internal.svmBlockField> => Utils.Set.t<string>),
|
|
531
|
+
),
|
|
532
|
+
~blockMaskFn=Svm.eventBlockFieldMask,
|
|
533
|
+
~transactionMaskFn=Svm.eventTransactionFieldMask,
|
|
422
534
|
)
|
|
423
535
|
{
|
|
424
536
|
id: switch discriminator {
|
|
@@ -433,10 +545,7 @@ let buildSvmInstructionEventConfig = (
|
|
|
433
545
|
discriminator,
|
|
434
546
|
discriminatorByteLen,
|
|
435
547
|
includeLogs,
|
|
436
|
-
|
|
437
|
-
transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
|
|
438
|
-
selectedBlockFields,
|
|
439
|
-
blockFieldMask,
|
|
548
|
+
fieldSelection,
|
|
440
549
|
accountFilters,
|
|
441
550
|
isInner,
|
|
442
551
|
accounts,
|
|
@@ -462,6 +571,7 @@ let buildSvmOnEventRegistration = (
|
|
|
462
571
|
filterByAddresses: false,
|
|
463
572
|
dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses=false),
|
|
464
573
|
startBlock,
|
|
574
|
+
fieldSelection: eventConfig.fieldSelection,
|
|
465
575
|
}
|
|
466
576
|
|
|
467
577
|
// ============== Build Fuel event config ==============
|
|
@@ -513,11 +623,15 @@ let buildFuelEventConfig = (
|
|
|
513
623
|
contractName,
|
|
514
624
|
paramsRawEventSchema: paramsSchema,
|
|
515
625
|
simulateParamsSchema: paramsSchema,
|
|
516
|
-
// Fuel keeps the transaction
|
|
517
|
-
//
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
626
|
+
// Fuel keeps the transaction inline on the payload, so nothing is selected
|
|
627
|
+
// for it; the block is materialised from the store with the full
|
|
628
|
+
// always-queried trio.
|
|
629
|
+
fieldSelection: Internal.makeFieldSelection(
|
|
630
|
+
~blockFields=Utils.Set.fromArray(Fuel.blockFields),
|
|
631
|
+
~transactionFields=Utils.Set.fromArray(Fuel.transactionFields),
|
|
632
|
+
~blockMaskFn=Fuel.eventBlockFieldMask,
|
|
633
|
+
~transactionMaskFn=Fuel.eventTransactionFieldMask,
|
|
634
|
+
),
|
|
521
635
|
kind: fuelKind,
|
|
522
636
|
}
|
|
523
637
|
}
|
|
@@ -539,4 +653,5 @@ let buildFuelOnEventRegistration = (
|
|
|
539
653
|
filterByAddresses: false,
|
|
540
654
|
dependsOnAddresses: Internal.dependsOnAddresses(~isWildcard, ~filterByAddresses=false),
|
|
541
655
|
startBlock,
|
|
656
|
+
fieldSelection: eventConfig.fieldSelection,
|
|
542
657
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as Evm from "./sources/Evm.res.mjs";
|
|
4
4
|
import * as Svm from "./sources/Svm.res.mjs";
|
|
5
5
|
import * as Core from "./Core.res.mjs";
|
|
6
|
+
import * as Fuel from "./sources/Fuel.res.mjs";
|
|
6
7
|
import * as Utils from "./Utils.res.mjs";
|
|
7
8
|
import * as Address from "./Address.res.mjs";
|
|
8
9
|
import * as FuelSDK from "./sources/FuelSDK.res.mjs";
|
|
@@ -237,10 +238,63 @@ let alwaysIncludedBlockFields = [
|
|
|
237
238
|
function resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet) {
|
|
238
239
|
let selectedBlockFields = blockFields !== undefined ? new Set(alwaysIncludedBlockFields.concat(blockFields)) : globalBlockFieldsSet;
|
|
239
240
|
let selectedTransactionFields = transactionFields !== undefined ? new Set(transactionFields) : globalTransactionFieldsSet;
|
|
240
|
-
return
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
241
|
+
return Internal.makeFieldSelection(selectedBlockFields, selectedTransactionFields, Evm.eventBlockFieldMask, Evm.eventTransactionFieldMask);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let internalBlockFields = ["number"];
|
|
245
|
+
|
|
246
|
+
let rawEventBlockFields = [
|
|
247
|
+
"hash",
|
|
248
|
+
"timestamp"
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
let selectionKinds = [
|
|
252
|
+
"block",
|
|
253
|
+
"transaction"
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
function validateFieldsShapeOrThrow(fields, registration) {
|
|
257
|
+
if (typeof fields !== "object" || fields === null || Array.isArray(fields)) {
|
|
258
|
+
Stdlib_JsError.throwWithMessage(`The fields option of ` + registration + ` must be an object of block and transaction field names.`);
|
|
259
|
+
}
|
|
260
|
+
Object.keys(fields).forEach(key => {
|
|
261
|
+
if (!selectionKinds.includes(key)) {
|
|
262
|
+
return Stdlib_JsError.throwWithMessage(`Invalid "` + key + `" key in the fields option of ` + registration + `. Valid keys: ` + selectionKinds.join(", ") + `.`);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
let validBlockFields = new Set(Evm.blockFields);
|
|
268
|
+
|
|
269
|
+
let validTransactionFields = new Set(Evm.transactionFields);
|
|
270
|
+
|
|
271
|
+
function parseFieldsOrThrow(fields, valid, kind, registration) {
|
|
272
|
+
let seen = new Set();
|
|
273
|
+
let fields$1 = fields !== undefined ? (
|
|
274
|
+
Array.isArray(fields) ? fields : Stdlib_JsError.throwWithMessage(`The fields.` + kind + ` option of ` + registration + ` must be an array of field names.`)
|
|
275
|
+
) : [];
|
|
276
|
+
fields$1.forEach(name => {
|
|
277
|
+
if (!valid.has(name)) {
|
|
278
|
+
Stdlib_JsError.throwWithMessage(`Invalid "` + name + `" field in the fields.` + kind + ` option of ` + registration + `. Valid ` + kind + ` fields: ` + Array.from(valid).join(", ") + `.`);
|
|
279
|
+
}
|
|
280
|
+
if (seen.has(name)) {
|
|
281
|
+
Stdlib_JsError.throwWithMessage(`Duplicate "` + name + `" field in the fields.` + kind + ` option of ` + registration + `.`);
|
|
282
|
+
}
|
|
283
|
+
seen.add(name);
|
|
284
|
+
});
|
|
285
|
+
return seen;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function resolveInlineFieldSelection(fields, contractName, eventName, enableRawEvents) {
|
|
289
|
+
let registration = `the "` + eventName + `" event registration on contract "` + contractName + `"`;
|
|
290
|
+
validateFieldsShapeOrThrow(fields, registration);
|
|
291
|
+
let blockFields = parseFieldsOrThrow(fields.block, validBlockFields, "block", registration);
|
|
292
|
+
let transactionFields = parseFieldsOrThrow(fields.transaction, validTransactionFields, "transaction", registration);
|
|
293
|
+
Utils.$$Set.addMany(blockFields, internalBlockFields);
|
|
294
|
+
if (enableRawEvents) {
|
|
295
|
+
Utils.$$Set.addMany(blockFields, rawEventBlockFields);
|
|
296
|
+
}
|
|
297
|
+
return Internal.makeFieldSelection(blockFields, transactionFields, Evm.eventBlockFieldMask, Evm.eventTransactionFieldMask);
|
|
244
298
|
}
|
|
245
299
|
|
|
246
300
|
function buildEvmEventConfig(contractName, eventName, sighash, params, blockFields, transactionFields, globalBlockFieldsSetOpt, globalTransactionFieldsSetOpt) {
|
|
@@ -253,26 +307,20 @@ function buildEvmEventConfig(contractName, eventName, sighash, params, blockFiel
|
|
|
253
307
|
return acc;
|
|
254
308
|
}
|
|
255
309
|
});
|
|
256
|
-
let match = resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet);
|
|
257
|
-
let selectedTransactionFields = match[1];
|
|
258
|
-
let selectedBlockFields = match[0];
|
|
259
310
|
return {
|
|
260
311
|
id: sighash + "_" + topicCount.toString(),
|
|
261
312
|
name: eventName,
|
|
262
313
|
contractName: contractName,
|
|
263
314
|
paramsRawEventSchema: buildParamsSchema(params),
|
|
264
315
|
simulateParamsSchema: buildSimulateParamsSchema(params),
|
|
265
|
-
|
|
266
|
-
transactionFieldMask: Evm.eventTransactionFieldMask(selectedTransactionFields),
|
|
267
|
-
blockFieldMask: Evm.eventBlockFieldMask(selectedBlockFields),
|
|
268
|
-
selectedBlockFields: selectedBlockFields,
|
|
316
|
+
fieldSelection: resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet),
|
|
269
317
|
sighash: sighash,
|
|
270
318
|
topicCount: topicCount,
|
|
271
319
|
paramsMetadata: params
|
|
272
320
|
};
|
|
273
321
|
}
|
|
274
322
|
|
|
275
|
-
function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, chainId, onEventBlockFilterSchema, startBlock) {
|
|
323
|
+
function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, chainId, onEventBlockFilterSchema, fieldSelection, startBlock) {
|
|
276
324
|
let indexedParams = eventConfig.paramsMetadata.filter(p => p.indexed);
|
|
277
325
|
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));
|
|
278
326
|
let filterByAddresses = match.filterByAddresses;
|
|
@@ -289,6 +337,7 @@ function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractR
|
|
|
289
337
|
dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, filterByAddresses),
|
|
290
338
|
addressFilterParamGroups: match.addressFilterParamGroups,
|
|
291
339
|
startBlock: resolvedStartBlock,
|
|
340
|
+
fieldSelection: fieldSelection !== undefined ? fieldSelection : eventConfig.fieldSelection,
|
|
292
341
|
resolvedWhere: resolvedWhere
|
|
293
342
|
};
|
|
294
343
|
}
|
|
@@ -306,19 +355,14 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
|
|
|
306
355
|
let args = argsOpt !== undefined ? argsOpt : null;
|
|
307
356
|
let definedTypes = definedTypesOpt !== undefined ? definedTypesOpt : null;
|
|
308
357
|
let paramsSchema = Utils.Schema.coerceToJsonPgType(S$RescriptSchema.json(false));
|
|
309
|
-
let
|
|
310
|
-
let selectedBlockFields = new Set(alwaysIncludedSvmBlockFields.concat(blockFields));
|
|
311
|
-
let blockFieldMask = Svm.eventBlockFieldMask(selectedBlockFields);
|
|
358
|
+
let fieldSelection = Internal.makeFieldSelection(new Set(alwaysIncludedSvmBlockFields.concat(blockFields)), new Set(transactionFields), Svm.eventBlockFieldMask, Svm.eventTransactionFieldMask);
|
|
312
359
|
return {
|
|
313
360
|
id: discriminator !== undefined ? discriminator : "none",
|
|
314
361
|
name: instructionName,
|
|
315
362
|
contractName: contractName,
|
|
316
363
|
paramsRawEventSchema: paramsSchema,
|
|
317
364
|
simulateParamsSchema: paramsSchema,
|
|
318
|
-
|
|
319
|
-
transactionFieldMask: Svm.eventTransactionFieldMask(selectedTransactionFields),
|
|
320
|
-
blockFieldMask: blockFieldMask,
|
|
321
|
-
selectedBlockFields: selectedBlockFields,
|
|
365
|
+
fieldSelection: fieldSelection,
|
|
322
366
|
programId: programId,
|
|
323
367
|
discriminator: discriminator,
|
|
324
368
|
discriminatorByteLen: discriminatorByteLen,
|
|
@@ -340,7 +384,8 @@ function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractR
|
|
|
340
384
|
isWildcard: isWildcard,
|
|
341
385
|
filterByAddresses: false,
|
|
342
386
|
dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
|
|
343
|
-
startBlock: startBlock
|
|
387
|
+
startBlock: startBlock,
|
|
388
|
+
fieldSelection: eventConfig.fieldSelection
|
|
344
389
|
};
|
|
345
390
|
}
|
|
346
391
|
|
|
@@ -393,9 +438,7 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
|
|
|
393
438
|
contractName: contractName,
|
|
394
439
|
paramsRawEventSchema: paramsSchema,
|
|
395
440
|
simulateParamsSchema: paramsSchema,
|
|
396
|
-
|
|
397
|
-
transactionFieldMask: 0,
|
|
398
|
-
blockFieldMask: 0,
|
|
441
|
+
fieldSelection: Internal.makeFieldSelection(new Set(Fuel.blockFields), new Set(Fuel.transactionFields), Fuel.eventBlockFieldMask, Fuel.eventTransactionFieldMask),
|
|
399
442
|
kind: fuelKind
|
|
400
443
|
};
|
|
401
444
|
}
|
|
@@ -409,7 +452,8 @@ function buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contract
|
|
|
409
452
|
isWildcard: isWildcard,
|
|
410
453
|
filterByAddresses: false,
|
|
411
454
|
dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
|
|
412
|
-
startBlock: startBlock
|
|
455
|
+
startBlock: startBlock,
|
|
456
|
+
fieldSelection: eventConfig.fieldSelection
|
|
413
457
|
};
|
|
414
458
|
}
|
|
415
459
|
|
|
@@ -428,6 +472,14 @@ export {
|
|
|
428
472
|
buildTopicGetter,
|
|
429
473
|
alwaysIncludedBlockFields,
|
|
430
474
|
resolveFieldSelection,
|
|
475
|
+
internalBlockFields,
|
|
476
|
+
rawEventBlockFields,
|
|
477
|
+
selectionKinds,
|
|
478
|
+
validateFieldsShapeOrThrow,
|
|
479
|
+
validBlockFields,
|
|
480
|
+
validTransactionFields,
|
|
481
|
+
parseFieldsOrThrow,
|
|
482
|
+
resolveInlineFieldSelection,
|
|
431
483
|
buildEvmEventConfig,
|
|
432
484
|
buildEvmOnEventRegistration,
|
|
433
485
|
alwaysIncludedSvmBlockFields,
|
package/src/EventProcessing.res
CHANGED
|
@@ -51,7 +51,7 @@ let runEventHandlerOrThrow = async (
|
|
|
51
51
|
isPreload: false,
|
|
52
52
|
chains,
|
|
53
53
|
config,
|
|
54
|
-
|
|
54
|
+
sync: UserContext.makeSyncState(),
|
|
55
55
|
}
|
|
56
56
|
await handler(
|
|
57
57
|
(
|
|
@@ -61,7 +61,7 @@ let runEventHandlerOrThrow = async (
|
|
|
61
61
|
}: Internal.handlerArgs
|
|
62
62
|
),
|
|
63
63
|
)
|
|
64
|
-
contextParams.
|
|
64
|
+
contextParams.sync.status = Resolved
|
|
65
65
|
} catch {
|
|
66
66
|
| exn =>
|
|
67
67
|
throw(
|
|
@@ -102,7 +102,7 @@ let runHandlerOrThrow = async (
|
|
|
102
102
|
isPreload: false,
|
|
103
103
|
chains,
|
|
104
104
|
config,
|
|
105
|
-
|
|
105
|
+
sync: UserContext.makeSyncState(),
|
|
106
106
|
}
|
|
107
107
|
await handler(
|
|
108
108
|
Ecosystem.makeOnBlockArgs(
|
|
@@ -111,7 +111,7 @@ let runHandlerOrThrow = async (
|
|
|
111
111
|
~context=UserContext.getHandlerContext(contextParams),
|
|
112
112
|
),
|
|
113
113
|
)
|
|
114
|
-
contextParams.
|
|
114
|
+
contextParams.sync.status = Resolved
|
|
115
115
|
} catch {
|
|
116
116
|
| exn =>
|
|
117
117
|
throw(
|
|
@@ -186,7 +186,7 @@ let preloadBatchOrThrow = async (
|
|
|
186
186
|
checkpointId,
|
|
187
187
|
isPreload: true,
|
|
188
188
|
chains,
|
|
189
|
-
|
|
189
|
+
sync: UserContext.makeSyncState(),
|
|
190
190
|
config,
|
|
191
191
|
}),
|
|
192
192
|
})
|
|
@@ -221,7 +221,7 @@ let preloadBatchOrThrow = async (
|
|
|
221
221
|
checkpointId,
|
|
222
222
|
isPreload: true,
|
|
223
223
|
chains,
|
|
224
|
-
|
|
224
|
+
sync: UserContext.makeSyncState(),
|
|
225
225
|
config,
|
|
226
226
|
}),
|
|
227
227
|
)
|
|
@@ -300,15 +300,11 @@ type logPartitionInfo = {
|
|
|
300
300
|
// for the batch's store-backed (HyperSync) items and write them onto the
|
|
301
301
|
// payloads, so handlers read plain objects. A batch can span chains, each with
|
|
302
302
|
// its own stores and field masks, so group items by chain before materialising.
|
|
303
|
-
let materializeBatchEvents = async (
|
|
304
|
-
batch: Batch.t,
|
|
305
|
-
~chainStates: dict<ChainState.t>,
|
|
306
|
-
~ecosystem,
|
|
307
|
-
) => {
|
|
303
|
+
let materializeBatchEvents = async (batch: Batch.t, ~chainStates: dict<ChainState.t>) => {
|
|
308
304
|
switch chainStates->Dict.valuesToArray {
|
|
309
305
|
// Single-chain indexers (the common case): every item belongs to the one
|
|
310
306
|
// chain, so skip the per-chain grouping and its allocations.
|
|
311
|
-
| [cs] => await cs->ChainState.materializeBatchItems(~items=batch.items
|
|
307
|
+
| [cs] => await cs->ChainState.materializeBatchItems(~items=batch.items)
|
|
312
308
|
| _ =>
|
|
313
309
|
let itemsByChain: dict<array<Internal.item>> = Dict.make()
|
|
314
310
|
batch.items->Array.forEach(item => {
|
|
@@ -323,7 +319,7 @@ let materializeBatchEvents = async (
|
|
|
323
319
|
->Dict.toArray
|
|
324
320
|
->Array.map(async ((chainId, items)) => {
|
|
325
321
|
let cs = chainStates->Dict.getUnsafe(chainId)
|
|
326
|
-
await cs->ChainState.materializeBatchItems(~items
|
|
322
|
+
await cs->ChainState.materializeBatchItems(~items)
|
|
327
323
|
})
|
|
328
324
|
->Promise.all
|
|
329
325
|
}
|
|
@@ -359,7 +355,7 @@ let processEventBatch = async (
|
|
|
359
355
|
if batch.items->Utils.Array.notEmpty {
|
|
360
356
|
// Materialise store-backed transactions onto payloads before any handler
|
|
361
357
|
// (preload or execute) reads them.
|
|
362
|
-
await materializeBatchEvents(batch, ~chainStates
|
|
358
|
+
await materializeBatchEvents(batch, ~chainStates)
|
|
363
359
|
await batch->preloadBatchOrThrow(~loadManager, ~persistence, ~indexerState, ~chains, ~config)
|
|
364
360
|
}
|
|
365
361
|
|
|
@@ -38,6 +38,7 @@ let ProcessingError = /* @__PURE__ */Primitive_exceptions.create("EventProcessin
|
|
|
38
38
|
async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState, loadManager, persistence, chains, config) {
|
|
39
39
|
let timeBeforeHandler = Performance.now();
|
|
40
40
|
try {
|
|
41
|
+
let contextParams_sync = UserContext.makeSyncState();
|
|
41
42
|
let contextParams = {
|
|
42
43
|
item: item,
|
|
43
44
|
checkpointId: checkpointId,
|
|
@@ -47,13 +48,13 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState,
|
|
|
47
48
|
isPreload: false,
|
|
48
49
|
chains: chains,
|
|
49
50
|
config: config,
|
|
50
|
-
|
|
51
|
+
sync: contextParams_sync
|
|
51
52
|
};
|
|
52
53
|
await handler({
|
|
53
54
|
event: Ecosystem.getItemEvent(item, config.ecosystem),
|
|
54
55
|
context: UserContext.getHandlerContext(contextParams)
|
|
55
56
|
});
|
|
56
|
-
|
|
57
|
+
contextParams_sync.status = "Resolved";
|
|
57
58
|
} catch (raw_exn) {
|
|
58
59
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
59
60
|
throw {
|
|
@@ -79,6 +80,7 @@ async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager,
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
try {
|
|
83
|
+
let contextParams_sync = UserContext.makeSyncState();
|
|
82
84
|
let contextParams = {
|
|
83
85
|
item: item,
|
|
84
86
|
checkpointId: checkpointId,
|
|
@@ -88,10 +90,10 @@ async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager,
|
|
|
88
90
|
isPreload: false,
|
|
89
91
|
chains: chains,
|
|
90
92
|
config: config,
|
|
91
|
-
|
|
93
|
+
sync: contextParams_sync
|
|
92
94
|
};
|
|
93
95
|
await item.onBlockRegistration.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext(contextParams)));
|
|
94
|
-
|
|
96
|
+
contextParams_sync.status = "Resolved";
|
|
95
97
|
return;
|
|
96
98
|
} catch (raw_exn) {
|
|
97
99
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
@@ -133,7 +135,7 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inde
|
|
|
133
135
|
isPreload: true,
|
|
134
136
|
chains: chains,
|
|
135
137
|
config: config,
|
|
136
|
-
|
|
138
|
+
sync: UserContext.makeSyncState()
|
|
137
139
|
})
|
|
138
140
|
}).then(() => IndexerState.endPreloadHandler(indexerState, timerRef, contractName, eventName))));
|
|
139
141
|
} catch (exn) {
|
|
@@ -151,7 +153,7 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inde
|
|
|
151
153
|
isPreload: true,
|
|
152
154
|
chains: chains,
|
|
153
155
|
config: config,
|
|
154
|
-
|
|
156
|
+
sync: UserContext.makeSyncState()
|
|
155
157
|
})))));
|
|
156
158
|
} catch (exn$1) {
|
|
157
159
|
|
|
@@ -186,7 +188,7 @@ function registerProcessEventBatchMetrics(logger, batch, indexerState, loadDurat
|
|
|
186
188
|
IndexerState.recordBatchDurations(indexerState, loadDuration, handlerDuration);
|
|
187
189
|
}
|
|
188
190
|
|
|
189
|
-
async function materializeBatchEvents(batch, chainStates
|
|
191
|
+
async function materializeBatchEvents(batch, chainStates) {
|
|
190
192
|
let match = Object.values(chainStates);
|
|
191
193
|
if (match.length !== 1) {
|
|
192
194
|
let itemsByChain = {};
|
|
@@ -201,12 +203,12 @@ async function materializeBatchEvents(batch, chainStates, ecosystem) {
|
|
|
201
203
|
});
|
|
202
204
|
await Promise.all(Object.entries(itemsByChain).map(async param => {
|
|
203
205
|
let cs = chainStates[param[0]];
|
|
204
|
-
return await ChainState.materializeBatchItems(cs, param[1]
|
|
206
|
+
return await ChainState.materializeBatchItems(cs, param[1]);
|
|
205
207
|
}));
|
|
206
208
|
return;
|
|
207
209
|
}
|
|
208
210
|
let cs = match[0];
|
|
209
|
-
return await ChainState.materializeBatchItems(cs, batch.items
|
|
211
|
+
return await ChainState.materializeBatchItems(cs, batch.items);
|
|
210
212
|
}
|
|
211
213
|
|
|
212
214
|
async function processEventBatch(batch, indexerState, loadManager, persistence, config, chainStates) {
|
|
@@ -221,7 +223,7 @@ async function processEventBatch(batch, indexerState, loadManager, persistence,
|
|
|
221
223
|
await Writing.awaitCapacity(indexerState);
|
|
222
224
|
let timeRef = Performance.now();
|
|
223
225
|
if (Utils.$$Array.notEmpty(batch.items)) {
|
|
224
|
-
await materializeBatchEvents(batch, chainStates
|
|
226
|
+
await materializeBatchEvents(batch, chainStates);
|
|
225
227
|
await preloadBatchOrThrow(batch, loadManager, persistence, config, indexerState, chains);
|
|
226
228
|
}
|
|
227
229
|
let elapsedTimeAfterLoaders = Performance.secondsSince(timeRef);
|