envio 3.3.0-alpha.1 → 3.3.0-alpha.3

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 (84) hide show
  1. package/index.d.ts +23 -21
  2. package/package.json +6 -6
  3. package/src/Batch.res +0 -6
  4. package/src/Batch.res.mjs +0 -11
  5. package/src/BatchProcessing.res +2 -12
  6. package/src/BatchProcessing.res.mjs +2 -7
  7. package/src/ChainFetching.res +42 -6
  8. package/src/ChainFetching.res.mjs +30 -11
  9. package/src/ChainMetadata.res +1 -11
  10. package/src/ChainMetadata.res.mjs +1 -10
  11. package/src/ChainState.res +150 -1
  12. package/src/ChainState.res.mjs +138 -9
  13. package/src/ChainState.resi +51 -1
  14. package/src/Config.res +3 -6
  15. package/src/Config.res.mjs +2 -3
  16. package/src/Core.res +7 -0
  17. package/src/CrossChainState.res +24 -26
  18. package/src/CrossChainState.res.mjs +19 -16
  19. package/src/Ecosystem.res +6 -3
  20. package/src/Envio.res +3 -2
  21. package/src/EventConfigBuilder.res +61 -23
  22. package/src/EventConfigBuilder.res.mjs +27 -13
  23. package/src/EventProcessing.res +63 -21
  24. package/src/EventProcessing.res.mjs +47 -22
  25. package/src/FetchState.res +53 -43
  26. package/src/FetchState.res.mjs +71 -54
  27. package/src/HandlerLoader.res +10 -1
  28. package/src/HandlerLoader.res.mjs +15 -8
  29. package/src/Internal.res +46 -7
  30. package/src/Internal.res.mjs +19 -1
  31. package/src/LoadLayer.res +5 -5
  32. package/src/LoadLayer.res.mjs +6 -6
  33. package/src/Main.res +3 -50
  34. package/src/Main.res.mjs +2 -23
  35. package/src/PgStorage.res +4 -4
  36. package/src/PgStorage.res.mjs +5 -5
  37. package/src/Prometheus.res +10 -10
  38. package/src/Prometheus.res.mjs +9 -9
  39. package/src/PruneStaleHistory.res +2 -2
  40. package/src/PruneStaleHistory.res.mjs +3 -3
  41. package/src/Rollback.res +3 -3
  42. package/src/Rollback.res.mjs +4 -4
  43. package/src/SimulateItems.res +80 -15
  44. package/src/SimulateItems.res.mjs +65 -21
  45. package/src/TestIndexer.res +48 -36
  46. package/src/TestIndexer.res.mjs +35 -28
  47. package/src/bindings/Performance.res +7 -0
  48. package/src/bindings/Performance.res.mjs +21 -0
  49. package/src/bindings/Performance.resi +7 -0
  50. package/src/sources/EventRouter.res +17 -21
  51. package/src/sources/EventRouter.res.mjs +6 -9
  52. package/src/sources/Evm.res +47 -67
  53. package/src/sources/Evm.res.mjs +42 -65
  54. package/src/sources/Fuel.res +3 -3
  55. package/src/sources/Fuel.res.mjs +1 -6
  56. package/src/sources/HyperFuelSource.res +15 -11
  57. package/src/sources/HyperFuelSource.res.mjs +13 -11
  58. package/src/sources/HyperSync.res +7 -1
  59. package/src/sources/HyperSync.res.mjs +6 -3
  60. package/src/sources/HyperSync.resi +2 -0
  61. package/src/sources/HyperSyncClient.res +14 -79
  62. package/src/sources/HyperSyncClient.res.mjs +1 -22
  63. package/src/sources/HyperSyncSource.res +44 -27
  64. package/src/sources/HyperSyncSource.res.mjs +32 -27
  65. package/src/sources/RpcSource.res +14 -10
  66. package/src/sources/RpcSource.res.mjs +11 -9
  67. package/src/sources/SimulateSource.res +4 -2
  68. package/src/sources/SimulateSource.res.mjs +1 -0
  69. package/src/sources/Source.res +5 -1
  70. package/src/sources/SourceManager.res +17 -16
  71. package/src/sources/SourceManager.res.mjs +10 -15
  72. package/src/sources/Svm.res +23 -6
  73. package/src/sources/Svm.res.mjs +24 -6
  74. package/src/sources/SvmHyperSyncClient.res +3 -29
  75. package/src/sources/SvmHyperSyncSource.res +78 -96
  76. package/src/sources/SvmHyperSyncSource.res.mjs +79 -91
  77. package/src/sources/TransactionStore.res +128 -0
  78. package/src/sources/TransactionStore.res.mjs +97 -0
  79. package/src/tui/Tui.res +13 -16
  80. package/src/tui/Tui.res.mjs +12 -14
  81. package/svm.schema.json +30 -37
  82. package/src/bindings/Hrtime.res +0 -58
  83. package/src/bindings/Hrtime.res.mjs +0 -90
  84. package/src/bindings/Hrtime.resi +0 -30
@@ -1,13 +1,16 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Utils from "./Utils.res.mjs";
4
- import * as Hrtime from "./bindings/Hrtime.res.mjs";
5
4
  import * as Logging from "./Logging.res.mjs";
6
5
  import * as Writing from "./Writing.res.mjs";
6
+ import * as Internal from "./Internal.res.mjs";
7
7
  import * as Ecosystem from "./Ecosystem.res.mjs";
8
8
  import * as ChainState from "./ChainState.res.mjs";
9
9
  import * as Prometheus from "./Prometheus.res.mjs";
10
+ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
11
+ import * as Performance from "./bindings/Performance.res.mjs";
10
12
  import * as Persistence from "./Persistence.res.mjs";
13
+ import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
11
14
  import * as UserContext from "./UserContext.res.mjs";
12
15
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
13
16
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
@@ -33,7 +36,7 @@ function computeChainsState(chainStates) {
33
36
  let ProcessingError = /* @__PURE__ */Primitive_exceptions.create("EventProcessing.ProcessingError");
34
37
 
35
38
  async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState, loadManager, persistence, chains, config) {
36
- let timeBeforeHandler = Hrtime.makeTimer();
39
+ let timeBeforeHandler = Performance.now();
37
40
  try {
38
41
  let contextParams = {
39
42
  item: item,
@@ -61,7 +64,7 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState,
61
64
  Error: new Error()
62
65
  };
63
66
  }
64
- let handlerDuration = Hrtime.toSecondsFloat(Hrtime.timeSince(timeBeforeHandler));
67
+ let handlerDuration = Performance.secondsSince(timeBeforeHandler);
65
68
  return Prometheus.ProcessingHandler.increment(item.eventConfig.contractName, item.eventConfig.name, handlerDuration);
66
69
  }
67
70
 
@@ -171,41 +174,62 @@ async function runBatchHandlersOrThrow(batch, indexerState, loadManager, persist
171
174
  }
172
175
  }
173
176
 
174
- function registerProcessEventBatchMetrics(logger, loadDuration, handlerDuration) {
175
- Logging.childTrace(logger, {
176
- msg: "Finished processing batch",
177
- loader_time_elapsed: loadDuration,
178
- handlers_time_elapsed: handlerDuration
179
- });
177
+ function registerProcessEventBatchMetrics(logger, batch, loadDuration, handlerDuration) {
178
+ Stdlib_Dict.forEachWithKey(batch.progressedChainsById, (chainAfterBatch, chainId) => Logging.childTrace(logger, {
179
+ msg: "Finished processing",
180
+ chainId: Stdlib_Int.fromString(chainId, undefined),
181
+ batchSize: chainAfterBatch.batchSize,
182
+ progress: chainAfterBatch.progressBlockNumber
183
+ }));
180
184
  Prometheus.ProcessingBatch.registerMetrics(loadDuration, handlerDuration);
181
185
  }
182
186
 
187
+ async function materializeBatchTransactions(batch, chainStates) {
188
+ let match = Object.values(chainStates);
189
+ if (match.length !== 1) {
190
+ let itemsByChain = {};
191
+ batch.items.forEach(item => {
192
+ let chainId = Internal.getItemChainId(item).toString();
193
+ let items = itemsByChain[chainId];
194
+ if (items !== undefined) {
195
+ items.push(item);
196
+ } else {
197
+ itemsByChain[chainId] = [item];
198
+ }
199
+ });
200
+ await Promise.all(Object.entries(itemsByChain).map(async param => {
201
+ let cs = chainStates[param[0]];
202
+ return await ChainState.materializeBatchItems(cs, param[1]);
203
+ }));
204
+ return;
205
+ }
206
+ let cs = match[0];
207
+ return await ChainState.materializeBatchItems(cs, batch.items);
208
+ }
209
+
183
210
  async function processEventBatch(batch, indexerState, loadManager, persistence, config, chainStates) {
184
- let totalBatchSize = batch.totalBatchSize;
185
211
  let chains = computeChainsState(chainStates);
186
212
  let logger = Logging.getLogger();
187
- Logging.childTrace(logger, {
188
- msg: "Started processing batch",
189
- totalBatchSize: totalBatchSize,
190
- chains: Utils.Dict.mapValues(batch.progressedChainsById, chainAfterBatch => ({
191
- batchSize: chainAfterBatch.batchSize,
192
- progress: chainAfterBatch.progressBlockNumber
193
- }))
194
- });
213
+ Stdlib_Dict.forEachWithKey(batch.progressedChainsById, (chainAfterBatch, chainId) => Logging.childTrace(logger, {
214
+ msg: "Started processing",
215
+ chainId: Stdlib_Int.fromString(chainId, undefined),
216
+ batchSize: chainAfterBatch.batchSize
217
+ }));
195
218
  try {
196
219
  await Writing.awaitCapacity(indexerState);
197
- let timeRef = Hrtime.makeTimer();
220
+ let timeRef = Performance.now();
198
221
  if (Utils.$$Array.notEmpty(batch.items)) {
222
+ await materializeBatchTransactions(batch, chainStates);
199
223
  await preloadBatchOrThrow(batch, loadManager, persistence, config, indexerState, chains);
200
224
  }
201
- let elapsedTimeAfterLoaders = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef));
225
+ let elapsedTimeAfterLoaders = Performance.secondsSince(timeRef);
202
226
  if (Utils.$$Array.notEmpty(batch.items)) {
203
227
  await runBatchHandlersOrThrow(batch, indexerState, loadManager, persistence, config, chains);
204
228
  }
205
- let elapsedTimeAfterProcessing = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef));
229
+ let elapsedTimeAfterProcessing = Performance.secondsSince(timeRef);
206
230
  Writing.commitBatch(indexerState, batch);
207
231
  let handlerDuration = elapsedTimeAfterProcessing - elapsedTimeAfterLoaders;
208
- registerProcessEventBatchMetrics(logger, elapsedTimeAfterLoaders, handlerDuration);
232
+ registerProcessEventBatchMetrics(logger, batch, elapsedTimeAfterLoaders, handlerDuration);
209
233
  return {
210
234
  TAG: "Ok",
211
235
  _0: undefined
@@ -240,6 +264,7 @@ export {
240
264
  preloadBatchOrThrow,
241
265
  runBatchHandlersOrThrow,
242
266
  registerProcessEventBatchMetrics,
267
+ materializeBatchTransactions,
243
268
  processEventBatch,
244
269
  }
245
270
  /* Utils Not a pure module */
@@ -41,6 +41,12 @@ type partition = {
41
41
  latestFetchedBlock: blockNumberAndTimestamp,
42
42
  selection: selection,
43
43
  addressesByContractName: dict<array<Address.t>>,
44
+ // Reverse index address→contractName, derived from addressesByContractName.
45
+ // Used by EventRouter to resolve a log's owning contract from the partition
46
+ // that fetched it (instead of a chain-wide snapshot). Always recomputed in
47
+ // OptimizedPartitions.make, so partition literals can seed it with an empty
48
+ // dict.
49
+ contractNameByAddress: dict<string>,
44
50
  mergeBlock: option<int>,
45
51
  // When set, partition indexes a single dynamic contract type.
46
52
  // The addressesByContractName must contain only addresses for this contract.
@@ -76,7 +82,23 @@ type query = {
76
82
  mutable progress: float,
77
83
  selection: selection,
78
84
  addressesByContractName: dict<array<Address.t>>,
79
- indexingAddresses: dict<indexingAddress>,
85
+ // The owning partition's reverse index, referenced (not copied) so routing
86
+ // resolves ownership without a chain-wide snapshot.
87
+ contractNameByAddress: dict<string>,
88
+ }
89
+
90
+ // Invert addressesByContractName into address→contractName. 1:1 today (each
91
+ // address belongs to one contract), so no key collisions.
92
+ let deriveContractNameByAddress = (addressesByContractName: dict<array<Address.t>>): dict<
93
+ string,
94
+ > => {
95
+ let result = Dict.make()
96
+ addressesByContractName->Utils.Dict.forEachWithKey((addresses, contractName) => {
97
+ for i in 0 to addresses->Array.length - 1 {
98
+ result->Dict.set(addresses->Array.getUnsafe(i)->Address.toString, contractName)
99
+ }
100
+ })
101
+ result
80
102
  }
81
103
 
82
104
  // Default estimate for a query whose partition hasn't responded yet, so the
@@ -192,6 +214,7 @@ module OptimizedPartitions = {
192
214
  latestFetchedBlock: {blockNumber: potentialMergeBlock, blockTimestamp: 0},
193
215
  mergeBlock: None,
194
216
  addressesByContractName: Dict.make(), // set below
217
+ contractNameByAddress: Dict.make(), // derived in make
195
218
  mutPendingQueries: [],
196
219
  prevQueryRange: minRange,
197
220
  prevPrevQueryRange: minRange,
@@ -374,7 +397,12 @@ module OptimizedPartitions = {
374
397
  for idx in 0 to partitionsCount - 1 {
375
398
  let p = newPartitions->Array.getUnsafe(idx)
376
399
  idsInAscOrder->Array.setUnsafe(idx, p.id)
377
- entities->Dict.set(p.id, p)
400
+ // Single point where every partition's reverse index is (re)derived, so all
401
+ // construction paths (literals, spreads, merges, splits) stay consistent.
402
+ entities->Dict.set(
403
+ p.id,
404
+ {...p, contractNameByAddress: deriveContractNameByAddress(p.addressesByContractName)},
405
+ )
378
406
  }
379
407
 
380
408
  {
@@ -873,6 +901,7 @@ OptimizedPartitions.t => {
873
901
  selection: normalSelection,
874
902
  dynamicContract: isDynamic ? Some(contractName) : None,
875
903
  addressesByContractName,
904
+ contractNameByAddress: Dict.make(), // derived in make
876
905
  mergeBlock: None,
877
906
  mutPendingQueries: [],
878
907
  prevQueryRange: 0,
@@ -1215,6 +1244,7 @@ let registerDynamicContracts = (
1215
1244
  selection: fetchState.normalSelection,
1216
1245
  dynamicContract: Some(contractName),
1217
1246
  addressesByContractName,
1247
+ contractNameByAddress: Dict.make(), // derived in make
1218
1248
  mergeBlock: None,
1219
1249
  mutPendingQueries: p.mutPendingQueries,
1220
1250
  prevQueryRange: p.prevQueryRange,
@@ -1329,6 +1359,9 @@ let startFetchingQueries = ({optimizedPartitions}: t, ~queries: array<query>) =>
1329
1359
  }
1330
1360
  }
1331
1361
 
1362
+ // Most parallel in-flight chunk queries a single partition may have at once.
1363
+ let maxPendingChunksPerPartition = 10
1364
+
1332
1365
  @inline
1333
1366
  let pushQueriesForRange = (
1334
1367
  queries: array<query>,
@@ -1337,12 +1370,12 @@ let pushQueriesForRange = (
1337
1370
  ~rangeEndBlock: option<int>,
1338
1371
  ~maxQueryBlockNumber: int,
1339
1372
  ~maybeChunkRange: option<int>,
1373
+ ~maxChunks: int,
1340
1374
  ~partition: partition,
1341
1375
  ~selection: selection,
1342
1376
  ~addressesByContractName: dict<array<Address.t>>,
1343
- ~indexingAddresses: dict<indexingAddress>,
1344
1377
  ) => {
1345
- if rangeFromBlock <= maxQueryBlockNumber {
1378
+ if rangeFromBlock <= maxQueryBlockNumber && maxChunks > 0 {
1346
1379
  switch rangeEndBlock {
1347
1380
  | Some(endBlock) if rangeFromBlock > endBlock => ()
1348
1381
  | _ =>
@@ -1363,7 +1396,7 @@ let pushQueriesForRange = (
1363
1396
  chainId: 0,
1364
1397
  progress: 0.,
1365
1398
  addressesByContractName,
1366
- indexingAddresses,
1399
+ contractNameByAddress: partition.contractNameByAddress,
1367
1400
  })
1368
1401
  | Some(chunkRange) =>
1369
1402
  let maxBlock = switch rangeEndBlock {
@@ -1371,18 +1404,13 @@ let pushQueriesForRange = (
1371
1404
  | None => maxQueryBlockNumber
1372
1405
  }
1373
1406
  let chunkSize = Js.Math.ceil_int(chunkRange->Int.toFloat *. 1.8)
1374
- // Probe with two smaller chunks first so their responses come back
1375
- // quickly and refresh the chunking heuristic, then three full-size chunks.
1376
- let probeSize = Js.Math.ceil_int(chunkRange->Int.toFloat *. 0.9)
1377
- let getChunkSize = chunkIdx => chunkIdx < 2 ? probeSize : chunkSize
1378
- if rangeFromBlock + getChunkSize(0) + getChunkSize(1) - 1 <= maxBlock {
1407
+ if rangeFromBlock + chunkSize * 2 - 1 <= maxBlock {
1379
1408
  let chunkFromBlock = ref(rangeFromBlock)
1380
1409
  let chunkIdx = ref(0)
1381
1410
  while (
1382
- chunkIdx.contents < 5 &&
1383
- chunkFromBlock.contents + getChunkSize(chunkIdx.contents) - 1 <= maxBlock
1411
+ chunkIdx.contents < maxChunks && chunkFromBlock.contents + chunkSize - 1 <= maxBlock
1384
1412
  ) {
1385
- let chunkToBlock = chunkFromBlock.contents + getChunkSize(chunkIdx.contents) - 1
1413
+ let chunkToBlock = chunkFromBlock.contents + chunkSize - 1
1386
1414
  queries->Array.push({
1387
1415
  partitionId,
1388
1416
  fromBlock: chunkFromBlock.contents,
@@ -1398,7 +1426,7 @@ let pushQueriesForRange = (
1398
1426
  chainId: 0,
1399
1427
  progress: 0.,
1400
1428
  addressesByContractName,
1401
- indexingAddresses,
1429
+ contractNameByAddress: partition.contractNameByAddress,
1402
1430
  })
1403
1431
  chunkFromBlock := chunkToBlock + 1
1404
1432
  chunkIdx := chunkIdx.contents + 1
@@ -1420,7 +1448,7 @@ let pushQueriesForRange = (
1420
1448
  chainId: 0,
1421
1449
  progress: 0.,
1422
1450
  addressesByContractName,
1423
- indexingAddresses,
1451
+ contractNameByAddress: partition.contractNameByAddress,
1424
1452
  })
1425
1453
  }
1426
1454
  }
@@ -1428,18 +1456,8 @@ let pushQueriesForRange = (
1428
1456
  }
1429
1457
  }
1430
1458
 
1431
- // Most parallel in-flight chunk queries a single partition may have at once.
1432
- let maxPendingChunksPerPartition = 10
1433
-
1434
1459
  let getNextQuery = (
1435
- {
1436
- buffer,
1437
- optimizedPartitions,
1438
- indexingAddresses,
1439
- blockLag,
1440
- latestOnBlockBlockNumber,
1441
- knownHeight,
1442
- } as fetchState: t,
1460
+ {buffer, optimizedPartitions, blockLag, latestOnBlockBlockNumber, knownHeight} as fetchState: t,
1443
1461
  ~budget,
1444
1462
  ~chainPendingBudget,
1445
1463
  ) => {
@@ -1533,10 +1551,13 @@ let getNextQuery = (
1533
1551
  ~rangeEndBlock=Utils.Math.minOptInt(Some(pq.fromBlock - 1), queryEndBlock),
1534
1552
  ~maxQueryBlockNumber,
1535
1553
  ~maybeChunkRange,
1554
+ ~maxChunks=maxPendingChunksPerPartition -
1555
+ pendingCount -
1556
+ (queries->Array.length -
1557
+ partitionQueriesStart),
1536
1558
  ~partition=p,
1537
1559
  ~selection=p.selection,
1538
1560
  ~addressesByContractName=p.addressesByContractName,
1539
- ~indexingAddresses,
1540
1561
  )
1541
1562
  }
1542
1563
  switch pq {
@@ -1558,28 +1579,16 @@ let getNextQuery = (
1558
1579
  ~rangeEndBlock=queryEndBlock,
1559
1580
  ~maxQueryBlockNumber,
1560
1581
  ~maybeChunkRange,
1582
+ ~maxChunks=maxPendingChunksPerPartition -
1583
+ pendingCount -
1584
+ (queries->Array.length -
1585
+ partitionQueriesStart),
1561
1586
  ~partition=p,
1562
1587
  ~selection=p.selection,
1563
1588
  ~addressesByContractName=p.addressesByContractName,
1564
- ~indexingAddresses,
1565
1589
  )
1566
1590
  }
1567
1591
 
1568
- // Cap parallel in-flight chunks per partition so a single partition can't
1569
- // monopolize fetching. Keep the earliest new chunks; the furthest-ahead
1570
- // ones wait for the next round once these resolve.
1571
- let maxNewChunks = Pervasives.max(0, maxPendingChunksPerPartition - pendingCount)
1572
- let generatedCount = queries->Array.length - partitionQueriesStart
1573
- if generatedCount > maxNewChunks {
1574
- queries
1575
- ->Array.splice(
1576
- ~start=partitionQueriesStart + maxNewChunks,
1577
- ~remove=generatedCount - maxNewChunks,
1578
- ~insert=[],
1579
- )
1580
- ->ignore
1581
- }
1582
-
1583
1592
  idxRef := idxRef.contents + 1
1584
1593
  }
1585
1594
 
@@ -1694,6 +1703,7 @@ let make = (
1694
1703
  eventConfigs: notDependingOnAddresses,
1695
1704
  },
1696
1705
  addressesByContractName: Dict.make(),
1706
+ contractNameByAddress: Dict.make(), // derived in make
1697
1707
  mergeBlock: None,
1698
1708
  dynamicContract: None,
1699
1709
  mutPendingQueries: [],