envio 3.7.0 → 3.9.0-resolvers.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.
Files changed (118) hide show
  1. package/README.md +2 -2
  2. package/evm.schema.json +7 -0
  3. package/fuel.schema.json +7 -0
  4. package/index.d.ts +674 -161
  5. package/index.js +10 -0
  6. package/package.json +6 -7
  7. package/src/AddressRows.res +121 -0
  8. package/src/AddressRows.res.mjs +143 -0
  9. package/src/Batch.res +11 -0
  10. package/src/Batch.res.mjs +2 -1
  11. package/src/Bin.res +47 -0
  12. package/src/Bin.res.mjs +34 -1
  13. package/src/ChainState.res +108 -98
  14. package/src/ChainState.res.mjs +86 -67
  15. package/src/ChainState.resi +28 -15
  16. package/src/Config.res +61 -131
  17. package/src/Config.res.mjs +47 -79
  18. package/src/ContractMapping.res +66 -0
  19. package/src/ContractMapping.res.mjs +73 -0
  20. package/src/Core.res +24 -0
  21. package/src/Core.res.mjs +4 -0
  22. package/src/Ecosystem.res +7 -2
  23. package/src/Env.res +128 -1
  24. package/src/Env.res.mjs +123 -1
  25. package/src/Envio.res +54 -76
  26. package/src/EventConfigBuilder.res +316 -46
  27. package/src/EventConfigBuilder.res.mjs +231 -28
  28. package/src/FetchState.res +59 -67
  29. package/src/FetchState.res.mjs +34 -44
  30. package/src/HandlerRegister.res +26 -15
  31. package/src/HandlerRegister.res.mjs +27 -7
  32. package/src/Hasura.res +30 -22
  33. package/src/Hasura.res.mjs +11 -5
  34. package/src/InMemoryStore.res +23 -38
  35. package/src/InMemoryStore.res.mjs +13 -27
  36. package/src/IndexerState.res +40 -3
  37. package/src/IndexerState.res.mjs +30 -4
  38. package/src/IndexerState.resi +4 -1
  39. package/src/Internal.res +49 -30
  40. package/src/Internal.res.mjs +12 -16
  41. package/src/Main.res +27 -20
  42. package/src/Main.res.mjs +19 -14
  43. package/src/Metrics.res +15 -1
  44. package/src/Metrics.res.mjs +5 -1
  45. package/src/Persistence.res +46 -21
  46. package/src/Persistence.res.mjs +8 -5
  47. package/src/PgStorage.res +238 -79
  48. package/src/PgStorage.res.mjs +115 -73
  49. package/src/PruneStaleHistory.res +1 -1
  50. package/src/PruneStaleHistory.res.mjs +1 -1
  51. package/src/Rollback.res +62 -41
  52. package/src/Rollback.res.mjs +61 -19
  53. package/src/RollbackCommit.res +7 -9
  54. package/src/RollbackCommit.res.mjs +5 -6
  55. package/src/SimulateItems.res +254 -9
  56. package/src/SimulateItems.res.mjs +214 -47
  57. package/src/Sink.res +35 -26
  58. package/src/Sink.res.mjs +20 -16
  59. package/src/TestIndexer.res +121 -123
  60. package/src/TestIndexer.res.mjs +97 -102
  61. package/src/Utils.res +38 -0
  62. package/src/Utils.res.mjs +39 -2
  63. package/src/Writing.res +4 -2
  64. package/src/Writing.res.mjs +3 -2
  65. package/src/bindings/ClickHouse.res +311 -656
  66. package/src/bindings/ClickHouse.res.mjs +294 -395
  67. package/src/bindings/ClickHouseSink.res +303 -0
  68. package/src/bindings/ClickHouseSink.res.mjs +216 -0
  69. package/src/bindings/NodeJs.res +9 -0
  70. package/src/bindings/NodeJs.res.mjs +8 -1
  71. package/src/bindings/Postgres.res +9 -0
  72. package/src/bindings/Postgres.res.mjs +3 -0
  73. package/src/db/EntityHistory.res +29 -24
  74. package/src/db/EntityHistory.res.mjs +11 -19
  75. package/src/db/InternalTable.res +258 -83
  76. package/src/db/InternalTable.res.mjs +223 -85
  77. package/src/db/RollbackScope.res +29 -0
  78. package/src/db/RollbackScope.res.mjs +31 -0
  79. package/src/db/Table.res +28 -1
  80. package/src/db/Table.res.mjs +26 -2
  81. package/src/resolvers/ResolverProcess.res +809 -0
  82. package/src/resolvers/ResolverProcess.res.mjs +667 -0
  83. package/src/resolvers/ResolverQuery.res +317 -0
  84. package/src/resolvers/ResolverQuery.res.mjs +220 -0
  85. package/src/resolvers/collisions.js +108 -0
  86. package/src/resolvers/db.js +363 -0
  87. package/src/resolvers/dispatch.js +165 -0
  88. package/src/resolvers/errors.js +30 -0
  89. package/src/resolvers/graphqlSelection.js +292 -0
  90. package/src/resolvers/hasuraAction.js +84 -0
  91. package/src/resolvers/hasuraApply.js +323 -0
  92. package/src/resolvers/hasuraMetadata.js +119 -0
  93. package/src/resolvers/index.js +95 -0
  94. package/src/resolvers/manifest.js +370 -0
  95. package/src/resolvers/server.js +270 -0
  96. package/src/sources/AddressSet.res +0 -22
  97. package/src/sources/AddressStore.res +48 -88
  98. package/src/sources/AddressStore.res.mjs +11 -22
  99. package/src/sources/Evm.res +2 -0
  100. package/src/sources/Evm.res.mjs +2 -0
  101. package/src/sources/EvmHyperSyncSource.res +3 -2
  102. package/src/sources/Fuel.res +2 -0
  103. package/src/sources/Fuel.res.mjs +2 -0
  104. package/src/sources/SimulateSource.res +8 -4
  105. package/src/sources/SimulateSource.res.mjs +7 -3
  106. package/src/sources/Svm.res +36 -7
  107. package/src/sources/Svm.res.mjs +34 -4
  108. package/src/sources/SvmHyperSyncClient.res +20 -116
  109. package/src/sources/SvmHyperSyncClient.res.mjs +5 -7
  110. package/src/sources/SvmHyperSyncSource.res +89 -37
  111. package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
  112. package/src/sources/TransactionStore.res +38 -0
  113. package/src/sources/TransactionStore.res.mjs +5 -0
  114. package/src/tui/Tui.res +1 -1
  115. package/src/tui/Tui.res.mjs +1 -1
  116. package/svm.schema.json +44 -156
  117. package/src/MemoryStorage.res +0 -724
  118. package/src/MemoryStorage.res.mjs +0 -601
@@ -14,6 +14,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
14
14
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
15
15
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
16
16
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
17
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
17
18
 
18
19
  let paramMetaSchema = S$RescriptSchema.recursive(self => S$RescriptSchema.object(s => ({
19
20
  name: s.f("name", S$RescriptSchema.string),
@@ -238,7 +239,7 @@ let alwaysIncludedBlockFields = [
238
239
  function resolveFieldSelection(blockFields, transactionFields, globalBlockFieldsSet, globalTransactionFieldsSet) {
239
240
  let selectedBlockFields = blockFields !== undefined ? new Set(alwaysIncludedBlockFields.concat(blockFields)) : globalBlockFieldsSet;
240
241
  let selectedTransactionFields = transactionFields !== undefined ? new Set(transactionFields) : globalTransactionFieldsSet;
241
- return Internal.makeFieldSelection(selectedBlockFields, selectedTransactionFields, Evm.eventBlockFieldMask, Evm.eventTransactionFieldMask);
242
+ return Internal.makeFieldSelection(selectedBlockFields, selectedTransactionFields, undefined, undefined, undefined, Evm.eventBlockFieldMask, Evm.eventTransactionFieldMask);
242
243
  }
243
244
 
244
245
  let internalBlockFields = ["number"];
@@ -248,53 +249,72 @@ let rawEventBlockFields = [
248
249
  "timestamp"
249
250
  ];
250
251
 
251
- let selectionKinds = [
252
+ let evmSelectionKinds = [
252
253
  "block",
253
254
  "transaction"
254
255
  ];
255
256
 
256
- function validateFieldsShapeOrThrow(fields, registration) {
257
+ let svmSelectionKinds = [
258
+ "instruction",
259
+ "transaction",
260
+ "accountActivity",
261
+ "block",
262
+ "log"
263
+ ];
264
+
265
+ function validateFieldsShapeOrThrow(fields, registration, validKeys, shapeNoun) {
257
266
  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.`);
267
+ Stdlib_JsError.throwWithMessage(`The fields option of ` + registration + ` must be an object of ` + shapeNoun + ` field names.`);
259
268
  }
260
269
  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(", ") + `.`);
270
+ if (!validKeys.includes(key)) {
271
+ return Stdlib_JsError.throwWithMessage(`Invalid "` + key + `" key in the fields option of ` + registration + `. Valid keys: ` + Utils.$$Array.quotedJoin(validKeys) + `.`);
263
272
  }
264
273
  });
265
274
  }
266
275
 
276
+ function selectionList(fields, key) {
277
+ let value = fields[key];
278
+ if (value !== undefined) {
279
+ return Primitive_option.valFromOption(value);
280
+ }
281
+ }
282
+
267
283
  let validBlockFields = new Set(Evm.blockFields);
268
284
 
269
285
  let validTransactionFields = new Set(Evm.transactionFields);
270
286
 
271
- function parseFieldsOrThrow(fields, valid, kind, registration) {
287
+ function parseFieldsOrThrow(fields, valid, kind, registration, rejectEmptyOpt) {
288
+ let rejectEmpty = rejectEmptyOpt !== undefined ? rejectEmptyOpt : false;
272
289
  let seen = new Set();
273
290
  let fields$1 = fields !== undefined ? (
274
291
  Array.isArray(fields) ? fields : Stdlib_JsError.throwWithMessage(`The fields.` + kind + ` option of ` + registration + ` must be an array of field names.`)
275
292
  ) : [];
276
293
  fields$1.forEach(name => {
277
294
  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(", ") + `.`);
295
+ Stdlib_JsError.throwWithMessage(`Invalid "` + name + `" field in the fields.` + kind + ` option of ` + registration + `. Valid ` + kind + ` fields: ` + Utils.$$Array.quotedJoin(Array.from(valid)) + `.`);
279
296
  }
280
297
  if (seen.has(name)) {
281
298
  Stdlib_JsError.throwWithMessage(`Duplicate "` + name + `" field in the fields.` + kind + ` option of ` + registration + `.`);
282
299
  }
283
300
  seen.add(name);
284
301
  });
302
+ if (rejectEmpty && fields$1.length === 0) {
303
+ Stdlib_JsError.throwWithMessage(`The fields.` + kind + ` option of ` + registration + ` must list at least one field.`);
304
+ }
285
305
  return seen;
286
306
  }
287
307
 
288
308
  function resolveInlineFieldSelection(fields, contractName, eventName, enableRawEvents) {
289
309
  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);
310
+ validateFieldsShapeOrThrow(fields, registration, evmSelectionKinds, "block and transaction");
311
+ let blockFields = parseFieldsOrThrow(selectionList(fields, "block"), validBlockFields, "block", registration, undefined);
312
+ let transactionFields = parseFieldsOrThrow(selectionList(fields, "transaction"), validTransactionFields, "transaction", registration, undefined);
293
313
  Utils.$$Set.addMany(blockFields, internalBlockFields);
294
314
  if (enableRawEvents) {
295
315
  Utils.$$Set.addMany(blockFields, rawEventBlockFields);
296
316
  }
297
- return Internal.makeFieldSelection(blockFields, transactionFields, Evm.eventBlockFieldMask, Evm.eventTransactionFieldMask);
317
+ return Internal.makeFieldSelection(blockFields, transactionFields, undefined, undefined, undefined, Evm.eventBlockFieldMask, Evm.eventTransactionFieldMask);
298
318
  }
299
319
 
300
320
  function buildEvmEventConfig(contractName, eventName, sighash, params, blockFields, transactionFields, globalBlockFieldsSetOpt, globalTransactionFieldsSetOpt) {
@@ -342,20 +362,83 @@ function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractR
342
362
  };
343
363
  }
344
364
 
345
- let alwaysIncludedSvmBlockFields = [
365
+ let alwaysIncludedSvmBlockFields = ["slot"];
366
+
367
+ let validSvmInstructionFields = new Set([
368
+ "args",
369
+ "accounts",
370
+ "accountArguments",
371
+ "programId",
372
+ "data",
373
+ "path",
374
+ "isInner"
375
+ ]);
376
+
377
+ let validSvmTransactionFields = new Set([
378
+ "transactionIndex",
379
+ "signature",
380
+ "feePayer",
381
+ "success",
382
+ "err",
383
+ "fee",
384
+ "computeUnitsConsumed",
385
+ "accountKeys",
386
+ "recentBlockhash",
387
+ "version",
388
+ "allSignatures"
389
+ ]);
390
+
391
+ let validSvmAccountActivityFields = new Set([
392
+ "address",
393
+ "transactionAccountIndex",
394
+ "isSigner",
395
+ "isWritable",
396
+ "lamports.pre",
397
+ "lamports.post",
398
+ "token.mint",
399
+ "token.owner",
400
+ "token.decimals",
401
+ "token.preAmount",
402
+ "token.postAmount"
403
+ ]);
404
+
405
+ let validSvmBlockFields = new Set([
346
406
  "slot",
347
407
  "time",
348
- "hash"
349
- ];
408
+ "hash",
409
+ "height",
410
+ "parentSlot",
411
+ "parentHash"
412
+ ]);
413
+
414
+ let validSvmLogFields = new Set([
415
+ "kind",
416
+ "message"
417
+ ]);
350
418
 
351
- function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, discriminatorByteLen, includeLogs, transactionFieldsOpt, blockFieldsOpt, accountFilters, isInner, accountsOpt, argsOpt, definedTypesOpt) {
352
- let transactionFields = transactionFieldsOpt !== undefined ? transactionFieldsOpt : [];
353
- let blockFields = blockFieldsOpt !== undefined ? blockFieldsOpt : [];
419
+ function resolveSvmInlineFieldSelection(fields, contractName, eventName) {
420
+ let registration = `the "` + eventName + `" instruction on program "` + contractName + `"`;
421
+ validateFieldsShapeOrThrow(fields, registration, svmSelectionKinds, "instruction, transaction, accountActivity, block and log");
422
+ let accountActivity = selectionList(fields, "accountActivity");
423
+ let log = selectionList(fields, "log");
424
+ let instructionFields = parseFieldsOrThrow(selectionList(fields, "instruction"), validSvmInstructionFields, "instruction", registration, undefined);
425
+ let transactionFields = parseFieldsOrThrow(selectionList(fields, "transaction"), validSvmTransactionFields, "transaction", registration, undefined);
426
+ let accountActivityFields = parseFieldsOrThrow(accountActivity, validSvmAccountActivityFields, "accountActivity", registration, Stdlib_Option.isSome(accountActivity));
427
+ let blockFields = parseFieldsOrThrow(selectionList(fields, "block"), validSvmBlockFields, "block", registration, undefined);
428
+ let logFields = parseFieldsOrThrow(log, validSvmLogFields, "log", registration, Stdlib_Option.isSome(log));
429
+ Utils.$$Set.addMany(blockFields, alwaysIncludedSvmBlockFields);
430
+ if (accountActivityFields.size > 0) {
431
+ transactionFields.add("accountActivities");
432
+ }
433
+ return Internal.makeFieldSelection(blockFields, transactionFields, Primitive_option.some(instructionFields), Primitive_option.some(accountActivityFields), Primitive_option.some(logFields), Svm.eventBlockFieldMask, Svm.eventTransactionFieldMask);
434
+ }
435
+
436
+ function buildSvmInstructionEventConfig(contractName, instructionName, programId, discriminator, accountsOpt, argsOpt, definedTypesOpt) {
354
437
  let accounts = accountsOpt !== undefined ? accountsOpt : [];
355
438
  let args = argsOpt !== undefined ? argsOpt : null;
356
439
  let definedTypes = definedTypesOpt !== undefined ? definedTypesOpt : null;
357
440
  let paramsSchema = Utils.Schema.coerceToJsonPgType(S$RescriptSchema.json(false));
358
- let fieldSelection = Internal.makeFieldSelection(new Set(alwaysIncludedSvmBlockFields.concat(blockFields)), new Set(transactionFields), Svm.eventBlockFieldMask, Svm.eventTransactionFieldMask);
441
+ let fieldSelection = Internal.makeFieldSelection(new Set(alwaysIncludedSvmBlockFields), new Set(), undefined, undefined, undefined, Svm.eventBlockFieldMask, Svm.eventTransactionFieldMask);
359
442
  return {
360
443
  id: discriminator !== undefined ? discriminator : "none",
361
444
  name: instructionName,
@@ -365,17 +448,121 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
365
448
  fieldSelection: fieldSelection,
366
449
  programId: programId,
367
450
  discriminator: discriminator,
368
- discriminatorByteLen: discriminatorByteLen,
369
- includeLogs: includeLogs,
370
- accountFilters: accountFilters,
371
- isInner: isInner,
372
451
  accounts: accounts,
373
452
  args: args,
374
453
  definedTypes: definedTypes
375
454
  };
376
455
  }
377
456
 
378
- function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
457
+ let validSvmWhereKeys = [
458
+ "accounts",
459
+ "isInner",
460
+ "block"
461
+ ];
462
+
463
+ let svmBlockFilterSchema = S$RescriptSchema.strict(S$RescriptSchema.object(s => ({
464
+ slot: s.f("slot", S$RescriptSchema.option(LogSelection.eventBlockRangeSchema))
465
+ })));
466
+
467
+ function resolveSvmWhereOrThrow(where, contractName, eventName, accountNames) {
468
+ let invalid = message => Stdlib_JsError.throwWithMessage(`Invalid where configuration for the "` + eventName + `" instruction on program "` + contractName + `". ` + message);
469
+ let obj;
470
+ obj = typeof where === "object" && where !== null && !Array.isArray(where) ? where : invalid("Expected an object.");
471
+ Utils.Dict.forEachWithKey(obj, (param, key) => {
472
+ if (!validSvmWhereKeys.includes(key)) {
473
+ return invalid(`Unknown field "` + key + `". Valid fields: ` + Utils.$$Array.quotedJoin(validSvmWhereKeys) + `.`);
474
+ }
475
+ });
476
+ let match = obj["isInner"];
477
+ let isInner = match !== undefined ? (
478
+ typeof match === "boolean" ? match : invalid(`The "isInner" filter must be a boolean.`)
479
+ ) : undefined;
480
+ let parseGroup = group => Object.entries(group).map(param => {
481
+ let name = param[0];
482
+ let position = accountNames.indexOf(name);
483
+ let position$1 = position !== -1 ? (
484
+ position >= 10 ? invalid(`Account "` + name + `" is at position ` + position.toString() + `, and only the first ` + (10).toString() + ` accounts of an instruction can be filtered.`) : position
485
+ ) : (
486
+ Utils.$$Array.isEmpty(accountNames) ? invalid("The instruction has no named accounts to filter on. Add `accounts` and `args` to it in config.yaml, or attach an IDL.") : invalid(`The instruction has no account named "` + name + `" to filter on. Named accounts: ` + Utils.$$Array.quotedJoin(accountNames) + `.`)
487
+ );
488
+ let values = normalizeOrThrow(param[1]);
489
+ if (Utils.$$Array.isEmpty(values)) {
490
+ invalid(`The "` + name + `" filter must list at least one pubkey.`);
491
+ }
492
+ return {
493
+ position: position$1,
494
+ values: values.map(value => {
495
+ if (typeof value === "string") {
496
+ if (Core.getAddon().isSvmPubkey(value)) {
497
+ return value;
498
+ } else {
499
+ return invalid(`The "` + name + `" filter value "` + value + `" is not a base58 SVM pubkey.`);
500
+ }
501
+ } else {
502
+ return invalid(`The "` + name + `" filter must list base58 pubkeys as strings.`);
503
+ }
504
+ })
505
+ };
506
+ });
507
+ let match$1 = obj["accounts"];
508
+ let groups;
509
+ if (match$1 !== undefined) {
510
+ if (Array.isArray(match$1)) {
511
+ groups = match$1.map(entry => {
512
+ if (typeof entry === "object" && entry !== null && !Array.isArray(entry)) {
513
+ return parseGroup(entry);
514
+ } else {
515
+ return invalid(`Each entry in "accounts" must be an object.`);
516
+ }
517
+ });
518
+ } else if (match$1 === null) {
519
+ groups = invalid(`Expected "accounts" to be an object or an array of objects.`);
520
+ } else {
521
+ switch (typeof match$1) {
522
+ case "object" :
523
+ groups = [parseGroup(match$1)];
524
+ break;
525
+ default:
526
+ groups = invalid(`Expected "accounts" to be an object or an array of objects.`);
527
+ }
528
+ }
529
+ } else {
530
+ groups = [];
531
+ }
532
+ let accountFilters = groups.some(Utils.$$Array.isEmpty) ? [] : groups;
533
+ let block = obj["block"];
534
+ let startBlock;
535
+ if (block !== undefined) {
536
+ let filter;
537
+ try {
538
+ filter = S$RescriptSchema.parseOrThrow(block, svmBlockFilterSchema);
539
+ } catch (raw_exn) {
540
+ let exn = Primitive_exceptions.internalToException(raw_exn);
541
+ if (exn.RE_EXN_ID === S$RescriptSchema.Raised) {
542
+ filter = invalid(`The "block" filter is invalid: ` + Utils.prettifyExn(exn._1) + `. Only \`_gte\` is supported on instruction filters — use \`indexer.onSlot\` for \`_lte\` or \`_every\`.`);
543
+ } else {
544
+ throw exn;
545
+ }
546
+ }
547
+ let match$2 = filter.slot;
548
+ startBlock = match$2 !== undefined ? match$2._gte : undefined;
549
+ } else {
550
+ startBlock = undefined;
551
+ }
552
+ return {
553
+ accountFilters: accountFilters,
554
+ isInner: isInner,
555
+ startBlock: startBlock
556
+ };
557
+ }
558
+
559
+ function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, fieldSelection, startBlock) {
560
+ let resolvedWhere = where !== undefined ? resolveSvmWhereOrThrow(where, eventConfig.contractName, eventConfig.name, eventConfig.accounts) : ({
561
+ accountFilters: [],
562
+ isInner: undefined,
563
+ startBlock: undefined
564
+ });
565
+ let sb = resolvedWhere.startBlock;
379
566
  return {
380
567
  index: -1,
381
568
  eventConfig: eventConfig,
@@ -384,8 +571,10 @@ function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractR
384
571
  isWildcard: isWildcard,
385
572
  filterByAddresses: false,
386
573
  dependsOnAddresses: Internal.dependsOnAddresses(isWildcard, false),
387
- startBlock: startBlock,
388
- fieldSelection: eventConfig.fieldSelection
574
+ startBlock: sb !== undefined ? sb : startBlock,
575
+ fieldSelection: fieldSelection !== undefined ? fieldSelection : eventConfig.fieldSelection,
576
+ accountFilters: resolvedWhere.accountFilters,
577
+ isInner: resolvedWhere.isInner
389
578
  };
390
579
  }
391
580
 
@@ -438,7 +627,7 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
438
627
  contractName: contractName,
439
628
  paramsRawEventSchema: paramsSchema,
440
629
  simulateParamsSchema: paramsSchema,
441
- fieldSelection: Internal.makeFieldSelection(new Set(Fuel.blockFields), new Set(Fuel.transactionFields), Fuel.eventBlockFieldMask, Fuel.eventTransactionFieldMask),
630
+ fieldSelection: Internal.makeFieldSelection(new Set(Fuel.blockFields), new Set(Fuel.transactionFields), undefined, undefined, undefined, Fuel.eventBlockFieldMask, Fuel.eventTransactionFieldMask),
442
631
  kind: fuelKind
443
632
  };
444
633
  }
@@ -457,6 +646,8 @@ function buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contract
457
646
  };
458
647
  }
459
648
 
649
+ let filterableAccountCount = 10;
650
+
460
651
  export {
461
652
  paramMetaSchema,
462
653
  normalizeOrThrow,
@@ -474,8 +665,10 @@ export {
474
665
  resolveFieldSelection,
475
666
  internalBlockFields,
476
667
  rawEventBlockFields,
477
- selectionKinds,
668
+ evmSelectionKinds,
669
+ svmSelectionKinds,
478
670
  validateFieldsShapeOrThrow,
671
+ selectionList,
479
672
  validBlockFields,
480
673
  validTransactionFields,
481
674
  parseFieldsOrThrow,
@@ -483,7 +676,17 @@ export {
483
676
  buildEvmEventConfig,
484
677
  buildEvmOnEventRegistration,
485
678
  alwaysIncludedSvmBlockFields,
679
+ validSvmInstructionFields,
680
+ validSvmTransactionFields,
681
+ validSvmAccountActivityFields,
682
+ validSvmBlockFields,
683
+ validSvmLogFields,
684
+ resolveSvmInlineFieldSelection,
486
685
  buildSvmInstructionEventConfig,
686
+ validSvmWhereKeys,
687
+ svmBlockFilterSchema,
688
+ filterableAccountCount,
689
+ resolveSvmWhereOrThrow,
487
690
  buildSvmOnEventRegistration,
488
691
  buildFuelEventConfig,
489
692
  buildFuelOnEventRegistration,
@@ -1469,7 +1469,6 @@ let warnAddressRegistration = (
1469
1469
 
1470
1470
  // A rejected registration is simply absent from every partition, so without a
1471
1471
  // warning the user sees a contract that never indexes and nothing saying why.
1472
- // Shared by config-time registration in `make` and by dynamic registration.
1473
1472
  let warnRejectedRegistration = (
1474
1473
  verdict: AddressStore.verdict,
1475
1474
  ~chainId: ChainId.t,
@@ -1477,20 +1476,7 @@ let warnRejectedRegistration = (
1477
1476
  ~contractName: string,
1478
1477
  ) =>
1479
1478
  switch verdict {
1480
- | Conflict({existingContractName}) =>
1481
- warnAddressRegistration(
1482
- ~chainId,
1483
- ~contractAddress,
1484
- ~params={
1485
- "existingContractType": existingContractName,
1486
- "newContractType": contractName,
1487
- },
1488
- `Skipping contract registration: Contract address is already registered for one contract and cannot be registered for another contract.`,
1489
- )
1490
1479
  | Duplicate({effectiveStartBlock, existingEffectiveStartBlock}) =>
1491
- // FIXME: Instead of filtering out duplicates, we should check the block
1492
- // number first. If a new registration has an earlier block number we
1493
- // should register it for the missing block range.
1494
1480
  if existingEffectiveStartBlock > effectiveStartBlock {
1495
1481
  warnAddressRegistration(
1496
1482
  ~chainId,
@@ -1499,7 +1485,7 @@ let warnRejectedRegistration = (
1499
1485
  "existingBlockNumber": existingEffectiveStartBlock,
1500
1486
  "newBlockNumber": effectiveStartBlock,
1501
1487
  },
1502
- `Skipping contract registration: Contract address is already registered at a later block number. Currently registration of the same contract address is not supported by Envio. Reach out to us if it's a problem for you.`,
1488
+ `Skipping same-contract re-registration: the address is already registered for this contract. The start block does not move earlier.`,
1503
1489
  )
1504
1490
  }
1505
1491
  | Invalid =>
@@ -1723,9 +1709,10 @@ let registerDynamicContracts = (
1723
1709
  // exactly what this batch adds.
1724
1710
  let idCursor = addressStore->AddressStore.nextId
1725
1711
  // The store resolves each address against both what it already holds and the
1726
- // batch's own earlier entries, so two contracts claiming one address inside a
1727
- // single batch conflict the same way as across batches. It also decides which
1728
- // additions this chain fetches for, since it's what holds the contract list.
1712
+ // batch's own earlier entries, so the same address registered twice for one
1713
+ // contract inside a single batch is a duplicate just as it is across batches.
1714
+ // It also decides which additions this chain fetches for, since it's what
1715
+ // holds the contract list.
1729
1716
  let verdicts = addressStore->AddressStore.registerBatch(registrations)
1730
1717
 
1731
1718
  let registeringContractNames = []
@@ -1741,7 +1728,7 @@ let registerDynamicContracts = (
1741
1728
  // no partition to build. The address is still stored and persisted, so a
1742
1729
  // config that later adds address-dependent events picks it up on restart.
1743
1730
  | Added({fetchable: false}) => ()
1744
- | Conflict(_) | Duplicate(_) | Invalid =>
1731
+ | Duplicate(_) | Invalid =>
1745
1732
  verdict->warnRejectedRegistration(
1746
1733
  ~chainId=fetchState.chainId,
1747
1734
  ~contractAddress=registration.address,
@@ -2627,7 +2614,7 @@ let make = (
2627
2614
  ~endBlock,
2628
2615
  ~onEventRegistrations: array<Internal.onEventRegistration>,
2629
2616
  ~addressStore: AddressStore.t,
2630
- ~addresses: array<Internal.indexingAddress>,
2617
+ ~addressRows: AddressRows.seedRows,
2631
2618
  ~maxAddrInPartition,
2632
2619
  ~chainId: ChainId.t,
2633
2620
  ~maxOnBlockBufferSize,
@@ -2681,27 +2668,24 @@ let make = (
2681
2668
  )
2682
2669
 
2683
2670
  // Every address the chain indexes goes into the store — including ones whose
2684
- // contract has no address-dependent events, so a later registration of the
2685
- // same address still conflicts and the address is still persisted.
2671
+ // contract has no address-dependent events, so the address is still persisted
2672
+ // and a config that later adds events picks it up.
2673
+ //
2674
+ // These rows come from the config or from a resume, so they're already stored
2675
+ // and must never be drained back into a write. Only the rows the store
2676
+ // refuses come back: a resume seeds millions of them.
2686
2677
  addressStore
2687
- // These come from the config or from a resume, so they're already stored and
2688
- // must never be drained back into a write.
2689
- ->AddressStore.seedBatch(
2690
- addresses->Array.map((contract): AddressStore.registration => {
2691
- address: contract.address,
2692
- contractName: contract.contractName,
2693
- registrationBlock: contract.registrationBlock,
2694
- }),
2695
- )
2696
- // Verdicts are in the batch's order, so they line up with `addresses`. A
2697
- // config address the store rejects is dropped exactly like a dynamic one, and
2698
- // needs the same warning — restored dynamic addresses come through here too.
2699
- ->Array.forEachWithIndex((verdict, idx) => {
2700
- let contract = addresses->Array.getUnsafe(idx)
2701
- verdict->warnRejectedRegistration(
2678
+ ->AddressStore.seedRows(addressRows)
2679
+ ->Array.forEach(rejected => {
2680
+ warnAddressRegistration(
2702
2681
  ~chainId,
2703
- ~contractAddress=contract.address,
2704
- ~contractName=contract.contractName,
2682
+ ~contractAddress=rejected.address,
2683
+ ~params={
2684
+ "contractName": rejected.contractName,
2685
+ "existingBlockNumber": rejected.existingEffectiveStartBlock,
2686
+ "newBlockNumber": rejected.effectiveStartBlock,
2687
+ },
2688
+ `Skipping a stored address: it is already registered for this contract.`,
2705
2689
  )
2706
2690
  })
2707
2691
 
@@ -2709,23 +2693,24 @@ let make = (
2709
2693
  let clientFilteredContracts = Utils.Set.make()
2710
2694
  let registeringSetsByContract = Dict.make()
2711
2695
 
2712
- addresses->Array.forEach(contract => {
2713
- let contractName = contract.contractName
2714
-
2715
- // Only addresses whose contract has events that depend on addresses get
2716
- // registered for active fetching via partitions.
2696
+ // What each contract needs a partition for is read back off the store rather
2697
+ // than re-derived from the seeded columns: the store is what resolved the
2698
+ // rows, including the ones it refused.
2699
+ contractNamesWithNormalEvents
2700
+ ->Utils.Set.toArray
2701
+ ->Array.forEach(contractName => {
2702
+ if addressStore->AddressStore.contractCount(contractName) > 0 {
2703
+ registeringSetsByContract->Dict.set(
2704
+ contractName,
2705
+ addressStore->AddressStore.makeSet(~contractName),
2706
+ )
2707
+ }
2708
+ })
2709
+ addressStore
2710
+ ->AddressStore.dynamicContractNames
2711
+ ->Array.forEach(contractName => {
2717
2712
  if contractNamesWithNormalEvents->Utils.Set.has(contractName) {
2718
- if !(registeringSetsByContract->Dict.has(contractName)) {
2719
- registeringSetsByContract->Dict.set(
2720
- contractName,
2721
- addressStore->AddressStore.makeSet(~contractName),
2722
- )
2723
- }
2724
-
2725
- // Detect dynamic contracts by registrationBlock
2726
- if contract.registrationBlock !== -1 {
2727
- dynamicContracts->Utils.Set.add(contractName)->ignore
2728
- }
2713
+ dynamicContracts->Utils.Set.add(contractName)->ignore
2729
2714
  }
2730
2715
  })
2731
2716
 
@@ -2768,7 +2753,7 @@ let make = (
2768
2753
  ) {
2769
2754
  JsError.throwWithMessage(
2770
2755
  `Invalid configuration: Nothing to fetch on chain ${chainId->ChainId.toString}. ` ++
2771
- `addresses=${addresses->Array.length->Int.toString}, ` ++
2756
+ `addresses=${addressRows.addresses->Array.length->Int.toString}, ` ++
2772
2757
  `onEventRegistrations=${onEventRegistrations->Array.length->Int.toString}, ` ++
2773
2758
  `normalRegistrations=${normalRegistrations
2774
2759
  ->Array.length
@@ -2845,20 +2830,28 @@ let rollbackPendingQueries = (mutPendingQueries: array<pendingQuery>, ~targetBlo
2845
2830
  adjusted
2846
2831
  }
2847
2832
 
2833
+ type rollbackResult = {
2834
+ fetchState: t,
2835
+ // The registrations the prune dropped, for the storage that deletes their rows.
2836
+ rolledBackAddresses: array<AddressStore.rolledBackAddress>,
2837
+ }
2838
+
2848
2839
  /**
2849
2840
  Rolls back fetch state to the given valid block.
2841
+ Prunes the store first, then rebuilds partitions from it: an address survives iff
2842
+ `filterByRegistrationBlock` keeps it, so the partitions and the rows the caller
2843
+ goes on to delete can't disagree about which registrations died.
2850
2844
  Always recreates optimized partitions to avoid duplicate addresses:
2851
2845
  - Wildcard: only rollback latestFetchedBlock
2852
2846
  - Non-wildcard with lfb <= target: keep, adjust pending queries and mergeBlock
2853
2847
  - Non-wildcard with lfb > target: delete, track addresses for recreation
2854
2848
  */
2855
- let rollback = (fetchState: t, ~addressStore: AddressStore.t, ~targetBlockNumber) => {
2856
- // Step 1: Prune addresses registered after the target block. The pruned store
2857
- // is then the source of truth for partition cleanup below — an address
2858
- // survives iff `filterByRegistrationBlock` keeps it.
2859
- addressStore->AddressStore.rollback(targetBlockNumber)->ignore
2860
-
2861
- // Step 2: Categorize partitions
2849
+ let rollback = (
2850
+ fetchState: t,
2851
+ ~rolledBackAddressStore: AddressStore.t,
2852
+ ~targetBlockNumber,
2853
+ ): rollbackResult => {
2854
+ let rolledBackAddresses = rolledBackAddressStore->AddressStore.rollback(targetBlockNumber)
2862
2855
  let keptPartitions = []
2863
2856
  let nextKeptIdRef = ref(0)
2864
2857
  let registeringSetsByContract: dict<AddressSet.t> = Dict.make()
@@ -2935,10 +2928,9 @@ let rollback = (fetchState: t, ~addressStore: AddressStore.t, ~targetBlockNumber
2935
2928
  }
2936
2929
  }
2937
2930
 
2938
- // Step 3: Recreate partitions from deleted partition addresses
2939
2931
  let optimizedPartitions = createPartitions(
2940
2932
  ~registeringSetsByContract,
2941
- ~addressStore,
2933
+ ~addressStore=rolledBackAddressStore,
2942
2934
  ~dynamicContracts=fetchState.optimizedPartitions.dynamicContracts,
2943
2935
  ~clientFilteredContracts=fetchState.optimizedPartitions.clientFilteredContracts,
2944
2936
  ~normalSelection=fetchState.normalSelection,
@@ -2949,8 +2941,7 @@ let rollback = (fetchState: t, ~addressStore: AddressStore.t, ~targetBlockNumber
2949
2941
  ~knownHeight=fetchState.knownHeight,
2950
2942
  )
2951
2943
 
2952
- // Step 4: Update state
2953
- {
2944
+ let rolledBack = {
2954
2945
  ...fetchState,
2955
2946
  // TODO: Test this. Currently it's not tested.
2956
2947
  latestOnBlockBlockNumber: Pervasives.min(
@@ -2969,6 +2960,7 @@ let rollback = (fetchState: t, ~addressStore: AddressStore.t, ~targetBlockNumber
2969
2960
  targetBlockNumber
2970
2961
  ),
2971
2962
  )
2963
+ {fetchState: rolledBack, rolledBackAddresses}
2972
2964
  }
2973
2965
 
2974
2966
  // Reset pending queries by removing in-flight queries (ones without fetchedBlock).