envio 3.3.0-alpha.9 → 3.3.0-rc.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 (94) hide show
  1. package/index.d.ts +19 -0
  2. package/licenses/CLA.md +35 -0
  3. package/licenses/EULA.md +67 -0
  4. package/licenses/LICENSE.md +45 -0
  5. package/licenses/README.md +35 -0
  6. package/package.json +9 -8
  7. package/src/Batch.res.mjs +1 -1
  8. package/src/BatchProcessing.res +0 -7
  9. package/src/BatchProcessing.res.mjs +1 -8
  10. package/src/ChainFetching.res +30 -18
  11. package/src/ChainFetching.res.mjs +23 -13
  12. package/src/ChainState.res +134 -55
  13. package/src/ChainState.res.mjs +78 -36
  14. package/src/ChainState.resi +14 -2
  15. package/src/Config.res +9 -5
  16. package/src/Config.res.mjs +2 -2
  17. package/src/Core.res +20 -0
  18. package/src/Core.res.mjs +12 -0
  19. package/src/CrossChainState.res +115 -34
  20. package/src/CrossChainState.res.mjs +37 -14
  21. package/src/EffectState.res +100 -0
  22. package/src/EffectState.res.mjs +74 -0
  23. package/src/EffectState.resi +32 -0
  24. package/src/Envio.res +25 -7
  25. package/src/Envio.res.mjs +15 -19
  26. package/src/EventConfigBuilder.res +21 -46
  27. package/src/EventConfigBuilder.res.mjs +18 -25
  28. package/src/EventProcessing.res +8 -5
  29. package/src/EventProcessing.res.mjs +2 -1
  30. package/src/FetchState.res +814 -467
  31. package/src/FetchState.res.mjs +541 -369
  32. package/src/HandlerRegister.res +3 -1
  33. package/src/HandlerRegister.res.mjs +3 -2
  34. package/src/InMemoryStore.res +14 -26
  35. package/src/InMemoryStore.res.mjs +6 -19
  36. package/src/IndexerState.res +15 -39
  37. package/src/IndexerState.res.mjs +18 -29
  38. package/src/IndexerState.resi +2 -10
  39. package/src/Internal.res +98 -14
  40. package/src/Internal.res.mjs +96 -2
  41. package/src/LoadLayer.res +44 -24
  42. package/src/LoadLayer.res.mjs +43 -20
  43. package/src/LoadLayer.resi +1 -0
  44. package/src/LogSelection.res +0 -62
  45. package/src/LogSelection.res.mjs +0 -74
  46. package/src/Metrics.res +1 -1
  47. package/src/Metrics.res.mjs +1 -1
  48. package/src/Persistence.res +12 -3
  49. package/src/PgStorage.res +155 -82
  50. package/src/PgStorage.res.mjs +130 -77
  51. package/src/Prometheus.res +20 -10
  52. package/src/Prometheus.res.mjs +22 -10
  53. package/src/PruneStaleHistory.res +146 -35
  54. package/src/PruneStaleHistory.res.mjs +114 -20
  55. package/src/RawEvent.res +2 -2
  56. package/src/Rollback.res +32 -13
  57. package/src/Rollback.res.mjs +24 -11
  58. package/src/SimulateDeadInputTracker.res +1 -1
  59. package/src/SimulateItems.res +38 -6
  60. package/src/SimulateItems.res.mjs +28 -9
  61. package/src/TestIndexer.res +2 -2
  62. package/src/TestIndexer.res.mjs +2 -2
  63. package/src/TopicFilter.res +1 -25
  64. package/src/TopicFilter.res.mjs +0 -74
  65. package/src/UserContext.res +62 -23
  66. package/src/UserContext.res.mjs +26 -6
  67. package/src/Writing.res +60 -21
  68. package/src/Writing.res.mjs +27 -9
  69. package/src/bindings/NodeJs.res +5 -0
  70. package/src/bindings/Viem.res +0 -5
  71. package/src/sources/EventRouter.res +0 -21
  72. package/src/sources/EventRouter.res.mjs +0 -12
  73. package/src/sources/EvmChain.res +2 -27
  74. package/src/sources/EvmChain.res.mjs +2 -23
  75. package/src/sources/EvmRpcClient.res +58 -23
  76. package/src/sources/EvmRpcClient.res.mjs +11 -5
  77. package/src/sources/HyperSync.res +9 -38
  78. package/src/sources/HyperSync.res.mjs +16 -28
  79. package/src/sources/HyperSync.resi +2 -2
  80. package/src/sources/HyperSyncClient.res +88 -11
  81. package/src/sources/HyperSyncClient.res.mjs +39 -6
  82. package/src/sources/HyperSyncSource.res +18 -199
  83. package/src/sources/HyperSyncSource.res.mjs +9 -128
  84. package/src/sources/Rpc.res +0 -32
  85. package/src/sources/Rpc.res.mjs +1 -46
  86. package/src/sources/RpcSource.res +129 -522
  87. package/src/sources/RpcSource.res.mjs +161 -366
  88. package/src/sources/SimulateSource.res +37 -19
  89. package/src/sources/SimulateSource.res.mjs +27 -10
  90. package/src/sources/SourceManager.res +3 -7
  91. package/src/sources/SourceManager.res.mjs +2 -7
  92. package/src/sources/SourceManager.resi +0 -2
  93. package/src/sources/SvmHyperSyncSource.res +13 -3
  94. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
@@ -1,8 +1,5 @@
1
1
  let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain.t): Source.t => {
2
- // getItemsOrThrow might be called multiple times with different partition ids.
3
- // Return all items on the first call and empty on subsequent calls to prevent
4
- // duplicate event processing.
5
- let delivered = ref(false)
2
+ let reportedHeight = max(endBlock, 1)
6
3
 
7
4
  {
8
5
  name: "SimulateSource",
@@ -16,38 +13,59 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
16
13
  },
17
14
  getHeightOrThrow: () => {
18
15
  // Report at least height 1 so the engine doesn't treat 0 as "no blocks available"
19
- Promise.resolve({Source.height: max(endBlock, 1), requestStats: []})
16
+ Promise.resolve({Source.height: reportedHeight, requestStats: []})
20
17
  },
21
18
  getItemsOrThrow: (
22
- ~fromBlock as _,
23
- ~toBlock as _,
19
+ ~fromBlock,
20
+ ~toBlock,
24
21
  ~addressesByContractName as _,
25
- ~contractNameByAddress as _,
22
+ ~contractNameByAddress,
26
23
  ~knownHeight as _,
27
24
  ~partitionId as _,
28
- ~selection as _,
25
+ ~selection: FetchState.selection,
29
26
  ~itemsTarget as _,
30
27
  ~retry as _,
31
28
  ~logger as _,
32
29
  ) => {
33
- // Return all items on the first call, empty on subsequent.
34
- let result = if delivered.contents {
35
- []
36
- } else {
37
- delivered := true
38
- items
30
+ // Mirror a real backend: return only the items this query would match —
31
+ // in the block range, part of the selection, and (for non-wildcard events)
32
+ // emitted by an address the partition is querying. Wildcard events are
33
+ // over-fetched regardless of srcAddress, leaving the client-side address
34
+ // filter to gate them exactly as it does for a HyperSync response. Overlapping
35
+ // queries may return the same item more than once; the buffer dedups it.
36
+ let toBlockQueried = switch toBlock {
37
+ | Some(toBlock) => toBlock
38
+ | None => reportedHeight
39
39
  }
40
+ let selectionEventIds = Utils.Set.make()
41
+ selection.onEventRegistrations->Array.forEach(reg =>
42
+ selectionEventIds->Utils.Set.add(reg.eventConfig.id)->ignore
43
+ )
44
+
45
+ let parsedQueueItems = items->Array.filter(item => {
46
+ let eventItem = item->Internal.castUnsafeEventItem
47
+ let {blockNumber, onEventRegistration} = eventItem
48
+ if blockNumber < fromBlock || blockNumber > toBlockQueried {
49
+ false
50
+ } else if !(selectionEventIds->Utils.Set.has(onEventRegistration.eventConfig.id)) {
51
+ false
52
+ } else if onEventRegistration.isWildcard {
53
+ true
54
+ } else {
55
+ let sa = eventItem.payload->Internal.getPayloadSrcAddress->Address.toString
56
+ contractNameByAddress->Utils.Dict.dangerouslyGetNonOption(sa)->Option.isSome
57
+ }
58
+ })
40
59
 
41
- let reportedHeight = max(endBlock, 1)
42
60
  Promise.resolve({
43
61
  Source.knownHeight: reportedHeight,
44
62
  blockHashes: [],
45
- parsedQueueItems: result,
63
+ parsedQueueItems,
46
64
  // Simulate keeps the transaction and block inline on the payload; no store pages.
47
65
  transactionStore: None,
48
66
  blockStore: None,
49
- fromBlockQueried: 0,
50
- latestFetchedBlockNumber: reportedHeight,
67
+ fromBlockQueried: fromBlock,
68
+ latestFetchedBlockNumber: toBlockQueried,
51
69
  latestFetchedBlockTimestamp: 0,
52
70
  stats: {
53
71
  totalTimeElapsed: 0.,
@@ -1,11 +1,10 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
4
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
5
 
5
6
  function make(items, endBlock, chain) {
6
- let delivered = {
7
- contents: false
8
- };
7
+ let reportedHeight = Primitive_int.max(endBlock, 1);
9
8
  return {
10
9
  name: "SimulateSource",
11
10
  sourceFor: "Sync",
@@ -20,20 +19,38 @@ function make(items, endBlock, chain) {
20
19
  requestStats: []
21
20
  }),
22
21
  getHeightOrThrow: () => Promise.resolve({
23
- height: Primitive_int.max(endBlock, 1),
22
+ height: reportedHeight,
24
23
  requestStats: []
25
24
  }),
26
- getItemsOrThrow: (param, param$1, param$2, param$3, param$4, param$5, param$6, param$7, param$8, param$9) => {
27
- let result = delivered.contents ? [] : (delivered.contents = true, items);
28
- let reportedHeight = Primitive_int.max(endBlock, 1);
25
+ getItemsOrThrow: (fromBlock, toBlock, param, contractNameByAddress, param$1, param$2, selection, param$3, param$4, param$5) => {
26
+ let toBlockQueried = toBlock !== undefined ? toBlock : reportedHeight;
27
+ let selectionEventIds = new Set();
28
+ selection.onEventRegistrations.forEach(reg => {
29
+ selectionEventIds.add(reg.eventConfig.id);
30
+ });
31
+ let parsedQueueItems = items.filter(item => {
32
+ let blockNumber = item.blockNumber;
33
+ if (blockNumber < fromBlock || blockNumber > toBlockQueried) {
34
+ return false;
35
+ }
36
+ let onEventRegistration = item.onEventRegistration;
37
+ if (!selectionEventIds.has(onEventRegistration.eventConfig.id)) {
38
+ return false;
39
+ }
40
+ if (onEventRegistration.isWildcard) {
41
+ return true;
42
+ }
43
+ let sa = item.payload.srcAddress;
44
+ return Stdlib_Option.isSome(contractNameByAddress[sa]);
45
+ });
29
46
  return Promise.resolve({
30
47
  knownHeight: reportedHeight,
31
48
  blockHashes: [],
32
- parsedQueueItems: result,
49
+ parsedQueueItems: parsedQueueItems,
33
50
  transactionStore: undefined,
34
51
  blockStore: undefined,
35
- fromBlockQueried: 0,
36
- latestFetchedBlockNumber: reportedHeight,
52
+ fromBlockQueried: fromBlock,
53
+ latestFetchedBlockNumber: toBlockQueried,
37
54
  latestFetchedBlockTimestamp: 0,
38
55
  stats: {
39
56
  "total time elapsed (s)": 0
@@ -1,4 +1,4 @@
1
- type sourceManagerStatus = Idle | WaitingForNewBlock | Querieng
1
+ type sourceManagerStatus = Idle | WaitingForNewBlock | Querying
2
2
 
3
3
  // Cumulative per-method request count/time for a source, aggregated from the
4
4
  // requestStat arrays returned by its methods. Rendered into
@@ -92,10 +92,6 @@ let getRequestStatSamples = (sourceManager: t): array<requestStatSample> => {
92
92
  samples
93
93
  }
94
94
 
95
- // Partition queries currently in flight on this chain's sources. Summed across
96
- // chains by CrossChainState to enforce the indexer-wide concurrency budget.
97
- let inFlightCount = sourceManager => sourceManager.fetchingPartitionsCount
98
-
99
95
  let getRateLimitTimeMs = sourceManager =>
100
96
  sourceManager.committedRateLimitTimeMs +.
101
97
  switch sourceManager.activeRateLimitStartMs {
@@ -259,7 +255,7 @@ let trackNewStatus = (sourceManager: t, ~newStatus) => {
259
255
  let promCounter = switch sourceManager.status {
260
256
  | Idle => Prometheus.IndexingIdleTime.counter
261
257
  | WaitingForNewBlock => Prometheus.IndexingSourceWaitingTime.counter
262
- | Querieng => Prometheus.IndexingQueryTime.counter
258
+ | Querying => Prometheus.IndexingQueryTime.counter
263
259
  }
264
260
  promCounter->Prometheus.SafeCounter.handleFloat(
265
261
  ~labels=sourceManager.activeSource.chain->ChainMap.Chain.toChainId,
@@ -311,7 +307,7 @@ let dispatch = async (
311
307
  ~concurrency=sourceManager.fetchingPartitionsCount,
312
308
  ~chainId=sourceManager.activeSource.chain->ChainMap.Chain.toChainId,
313
309
  )
314
- sourceManager->trackNewStatus(~newStatus=Querieng)
310
+ sourceManager->trackNewStatus(~newStatus=Querying)
315
311
  let _ = await queries
316
312
  ->Array.map(q => {
317
313
  let promise = q->executeQuery
@@ -52,10 +52,6 @@ function getRequestStatSamples(sourceManager) {
52
52
  return samples;
53
53
  }
54
54
 
55
- function inFlightCount(sourceManager) {
56
- return sourceManager.fetchingPartitionsCount;
57
- }
58
-
59
55
  function getRateLimitTimeMs(sourceManager) {
60
56
  let startMs = sourceManager.activeRateLimitStartMs;
61
57
  return sourceManager.committedRateLimitTimeMs + (
@@ -204,7 +200,7 @@ function trackNewStatus(sourceManager, newStatus) {
204
200
  case "WaitingForNewBlock" :
205
201
  promCounter = Prometheus.IndexingSourceWaitingTime.counter;
206
202
  break;
207
- case "Querieng" :
203
+ case "Querying" :
208
204
  promCounter = Prometheus.IndexingQueryTime.counter;
209
205
  break;
210
206
  }
@@ -237,7 +233,7 @@ async function dispatch(sourceManager, fetchState, executeQuery, waitForNewBlock
237
233
  let queries = action._0;
238
234
  sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount + queries.length | 0;
239
235
  Prometheus.IndexingConcurrency.set(sourceManager.fetchingPartitionsCount, sourceManager.activeSource.chain);
240
- trackNewStatus(sourceManager, "Querieng");
236
+ trackNewStatus(sourceManager, "Querying");
241
237
  await Promise.all(queries.map(q => {
242
238
  let promise = executeQuery(q);
243
239
  promise.then(param => {
@@ -719,7 +715,6 @@ export {
719
715
  make,
720
716
  getActiveSource,
721
717
  getRequestStatSamples,
722
- inFlightCount,
723
718
  onReorg,
724
719
  dispatch,
725
720
  waitForNewBlock,
@@ -31,8 +31,6 @@ type requestStatSample = {
31
31
 
32
32
  let getRequestStatSamples: t => array<requestStatSample>
33
33
 
34
- let inFlightCount: t => int
35
-
36
34
  let onReorg: (t, ~rollbackTargetBlock: int) => unit
37
35
 
38
36
  let dispatch: (
@@ -285,8 +285,8 @@ let make = (
285
285
  ): t => {
286
286
  let name = "SvmHyperSync"
287
287
 
288
- // Definitions drive query/decode building; the registrations drive routing
289
- // (they carry `isWildcard` and become each decoded item's `onEventRegistration`).
288
+ // Definitions drive query/decode building; registrations drive routing and
289
+ // are attached directly to decoded runtime items.
290
290
  let eventConfigs =
291
291
  onEventRegistrations->Array.map(reg =>
292
292
  reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.svmInstructionEventConfig)
@@ -488,6 +488,16 @@ let make = (
488
488
 
489
489
  switch maybeConfig {
490
490
  | None => ()
491
+ // Exclude instructions from failed transactions. HyperSync has no
492
+ // server-side predicate to filter instructions by parent-transaction
493
+ // success (`InstructionSelection` only exposes `is_inner`, and
494
+ // instruction/transaction selections union at block level rather than
495
+ // joining), so we filter client-side on the `isCommitted` flag HyperSync
496
+ // already delivers on every instruction row (a required column, zero extra
497
+ // bandwidth). When HyperSync adds a server-side `is_committed` predicate the
498
+ // query can push this down and the client-side check becomes a redundant
499
+ // safety net.
500
+ | Some(_) if !instr.isCommitted => ()
491
501
  | Some(onEventRegistration) =>
492
502
  let eventConfig =
493
503
  onEventRegistration.eventConfig->(
@@ -521,7 +531,7 @@ let make = (
521
531
  parsedQueueItems
522
532
  ->Array.push(
523
533
  Internal.Event({
524
- onEventRegistration,
534
+ onEventRegistration: (onEventRegistration :> Internal.onEventRegistration),
525
535
  chain,
526
536
  blockNumber: instr.slot,
527
537
  logIndex: synthLogIndex(instr),
@@ -415,7 +415,7 @@ function make(param) {
415
415
  let byteLengths = Stdlib_Option.getOr(orderingByProgram[instr.programId], []);
416
416
  let contractAddress = instr.programId;
417
417
  let maybeConfig = probeRouter(eventRouter, programId, instr, byteLengths, contractAddress, contractNameByAddress);
418
- if (maybeConfig !== undefined) {
418
+ if (maybeConfig !== undefined && instr.isCommitted) {
419
419
  let eventConfig = maybeConfig.eventConfig;
420
420
  let logKey = instr.slot.toString() + ":" + instr.transactionIndex.toString() + ":" + serializeInstructionAddress(instr.instructionAddress);
421
421
  let maybeLogs = Stdlib_Option.map(logsByKey[logKey], logs => logs.map(log => ({