envio 3.6.1 → 3.7.0
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 +9 -2
- package/src/Config.res.mjs +4 -4
- package/src/Core.res +5 -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 +4 -8
- package/src/EventProcessing.res.mjs +4 -4
- package/src/EventUtils.res +3 -47
- package/src/FetchState.res +124 -104
- package/src/FetchState.res.mjs +116 -100
- package/src/HandlerRegister.res +108 -2
- package/src/HandlerRegister.res.mjs +59 -10
- package/src/HandlerRegister.resi +4 -0
- 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 +724 -0
- package/src/MemoryStorage.res.mjs +601 -0
- package/src/PgStorage.res +18 -7
- package/src/PgStorage.res.mjs +14 -11
- 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/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/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
|
@@ -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
|
|
|
@@ -186,7 +186,7 @@ function registerProcessEventBatchMetrics(logger, batch, indexerState, loadDurat
|
|
|
186
186
|
IndexerState.recordBatchDurations(indexerState, loadDuration, handlerDuration);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
async function materializeBatchEvents(batch, chainStates
|
|
189
|
+
async function materializeBatchEvents(batch, chainStates) {
|
|
190
190
|
let match = Object.values(chainStates);
|
|
191
191
|
if (match.length !== 1) {
|
|
192
192
|
let itemsByChain = {};
|
|
@@ -201,12 +201,12 @@ async function materializeBatchEvents(batch, chainStates, ecosystem) {
|
|
|
201
201
|
});
|
|
202
202
|
await Promise.all(Object.entries(itemsByChain).map(async param => {
|
|
203
203
|
let cs = chainStates[param[0]];
|
|
204
|
-
return await ChainState.materializeBatchItems(cs, param[1]
|
|
204
|
+
return await ChainState.materializeBatchItems(cs, param[1]);
|
|
205
205
|
}));
|
|
206
206
|
return;
|
|
207
207
|
}
|
|
208
208
|
let cs = match[0];
|
|
209
|
-
return await ChainState.materializeBatchItems(cs, batch.items
|
|
209
|
+
return await ChainState.materializeBatchItems(cs, batch.items);
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
async function processEventBatch(batch, indexerState, loadManager, persistence, config, chainStates) {
|
|
@@ -221,7 +221,7 @@ async function processEventBatch(batch, indexerState, loadManager, persistence,
|
|
|
221
221
|
await Writing.awaitCapacity(indexerState);
|
|
222
222
|
let timeRef = Performance.now();
|
|
223
223
|
if (Utils.$$Array.notEmpty(batch.items)) {
|
|
224
|
-
await materializeBatchEvents(batch, chainStates
|
|
224
|
+
await materializeBatchEvents(batch, chainStates);
|
|
225
225
|
await preloadBatchOrThrow(batch, loadManager, persistence, config, indexerState, chains);
|
|
226
226
|
}
|
|
227
227
|
let elapsedTimeAfterLoaders = Performance.secondsSince(timeRef);
|
package/src/EventUtils.res
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// }
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
// takes blockNumber, logIndex and packs them into a number with
|
|
8
|
-
//32 bits, 16 bits and 16 bits respectively
|
|
1
|
+
// Packs blockNumber and logIndex into one number: 32 bits and 16 bits
|
|
2
|
+
// respectively. EVM only — it is the `raw_events.event_id` primary value, and
|
|
3
|
+
// no other ecosystem writes that table.
|
|
9
4
|
let packEventIndex = (~blockNumber, ~logIndex) => {
|
|
10
5
|
let blockNumber = blockNumber->BigInt.fromInt
|
|
11
6
|
let logIndex = logIndex->BigInt.fromInt
|
|
@@ -13,42 +8,3 @@ let packEventIndex = (~blockNumber, ~logIndex) => {
|
|
|
13
8
|
|
|
14
9
|
blockNumber->BigInt.bitwiseOr(logIndex)
|
|
15
10
|
}
|
|
16
|
-
|
|
17
|
-
// //Currently not used but keeping in utils
|
|
18
|
-
// //using @live flag for dead code analyser
|
|
19
|
-
// @live
|
|
20
|
-
// let packMultiChainEventIndex = (~timestamp, ~chainId, ~blockNumber, ~logIndex) => {
|
|
21
|
-
// let timestamp = timestamp->BigInt.fromInt
|
|
22
|
-
// let chainId = chainId->BigInt.fromInt
|
|
23
|
-
// let blockNumber = blockNumber->BigInt.fromInt
|
|
24
|
-
// let logIndex = logIndex->BigInt.fromInt
|
|
25
|
-
|
|
26
|
-
// let timestamp = BigInt.shiftLeft(timestamp, 48->BigInt.fromInt)
|
|
27
|
-
// let chainId = BigInt.shiftLeft(chainId, 16->BigInt.fromInt)
|
|
28
|
-
// let blockNumber = BigInt.shiftLeft(blockNumber, 16->BigInt.fromInt)
|
|
29
|
-
|
|
30
|
-
// timestamp
|
|
31
|
-
// ->BigInt.bitwiseOr(chainId)
|
|
32
|
-
// ->BigInt.bitwiseOr(blockNumber)
|
|
33
|
-
// ->BigInt.bitwiseOr(logIndex)
|
|
34
|
-
// }
|
|
35
|
-
|
|
36
|
-
// //Currently not used but keeping in utils
|
|
37
|
-
// //using @live flag for dead code analyser
|
|
38
|
-
// @live
|
|
39
|
-
// let unpackEventIndex = (packedEventIndex: bigint) => {
|
|
40
|
-
// let blockNumber = packedEventIndex->BigInt.shiftRight(16->BigInt.fromInt)
|
|
41
|
-
// let logIndexMask = 65535->BigInt.fromInt
|
|
42
|
-
// let logIndex = packedEventIndex->BigInt.bitwiseAnd(logIndexMask)
|
|
43
|
-
// {
|
|
44
|
-
// blockNumber: blockNumber->BigInt.toString->Int.fromString->Option.getUnsafe,
|
|
45
|
-
// logIndex: logIndex->BigInt.toString->Int.fromString->Option.getUnsafe,
|
|
46
|
-
// }
|
|
47
|
-
// }
|
|
48
|
-
|
|
49
|
-
// //takes an eventIndex record and returnts a packed event index
|
|
50
|
-
// //used in TS tests
|
|
51
|
-
// @live
|
|
52
|
-
// let packEventIndexFromRecord = (eventIndex: eventIndex) => {
|
|
53
|
-
// packEventIndex(~blockNumber=eventIndex.blockNumber, ~logIndex=eventIndex.logIndex)
|
|
54
|
-
// }
|