envio 3.5.0-alpha.2 → 3.5.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 (129) hide show
  1. package/package.json +6 -6
  2. package/src/Batch.res +8 -8
  3. package/src/Batch.res.mjs +4 -3
  4. package/src/BatchProcessing.res +24 -0
  5. package/src/BatchProcessing.res.mjs +12 -0
  6. package/src/ChainFetching.res +20 -19
  7. package/src/ChainFetching.res.mjs +14 -14
  8. package/src/ChainId.res +58 -0
  9. package/src/ChainId.res.mjs +49 -0
  10. package/src/ChainId.resi +27 -0
  11. package/src/ChainMap.res +12 -26
  12. package/src/ChainMap.res.mjs +5 -41
  13. package/src/ChainMap.resi +5 -20
  14. package/src/ChainMetadata.res +1 -1
  15. package/src/ChainMetadata.res.mjs +3 -2
  16. package/src/ChainState.res +45 -24
  17. package/src/ChainState.res.mjs +40 -16
  18. package/src/ChainState.resi +3 -1
  19. package/src/Config.res +43 -26
  20. package/src/Config.res.mjs +19 -16
  21. package/src/ContractRegisterContext.res +1 -1
  22. package/src/ContractRegisterContext.res.mjs +1 -1
  23. package/src/Core.res +1 -0
  24. package/src/CrossChainState.res +90 -22
  25. package/src/CrossChainState.res.mjs +55 -16
  26. package/src/CrossChainState.resi +5 -1
  27. package/src/Env.res +0 -3
  28. package/src/Env.res.mjs +0 -3
  29. package/src/EventConfigBuilder.res +1 -1
  30. package/src/EventProcessing.res +4 -4
  31. package/src/EventProcessing.res.mjs +5 -5
  32. package/src/FetchState.res +489 -153
  33. package/src/FetchState.res.mjs +399 -129
  34. package/src/FinalizeBackfill.res +61 -0
  35. package/src/FinalizeBackfill.res.mjs +44 -0
  36. package/src/HandlerRegister.res +8 -8
  37. package/src/HandlerRegister.res.mjs +5 -4
  38. package/src/HandlerRegister.resi +1 -1
  39. package/src/InMemoryStore.res +4 -0
  40. package/src/InMemoryStore.res.mjs +1 -1
  41. package/src/InMemoryTable.res +15 -15
  42. package/src/InMemoryTable.res.mjs +14 -14
  43. package/src/IndexerLoop.res +9 -2
  44. package/src/IndexerLoop.res.mjs +8 -1
  45. package/src/IndexerState.res +52 -23
  46. package/src/IndexerState.res.mjs +52 -14
  47. package/src/IndexerState.resi +11 -6
  48. package/src/Internal.res +19 -17
  49. package/src/Internal.res.mjs +18 -9
  50. package/src/LoadLayer.res +10 -2
  51. package/src/LoadLayer.res.mjs +3 -1
  52. package/src/LogSelection.res +2 -2
  53. package/src/Main.res +7 -11
  54. package/src/Main.res.mjs +4 -6
  55. package/src/Metrics.res +6 -6
  56. package/src/Metrics.res.mjs +4 -3
  57. package/src/Persistence.res +23 -4
  58. package/src/PgStorage.res +447 -100
  59. package/src/PgStorage.res.mjs +285 -99
  60. package/src/RawEvent.res +1 -2
  61. package/src/RawEvent.res.mjs +1 -1
  62. package/src/Rollback.res +18 -20
  63. package/src/Rollback.res.mjs +9 -9
  64. package/src/RollbackCommit.res +2 -2
  65. package/src/RollbackCommit.res.mjs +3 -3
  66. package/src/SafeCheckpointTracking.res +2 -2
  67. package/src/SimulateDeadInputTracker.res +17 -21
  68. package/src/SimulateDeadInputTracker.res.mjs +9 -8
  69. package/src/SimulateItems.res +8 -10
  70. package/src/SimulateItems.res.mjs +9 -10
  71. package/src/Sink.res +2 -2
  72. package/src/Sink.res.mjs +3 -2
  73. package/src/TestIndexer.res +14 -14
  74. package/src/TestIndexer.res.mjs +16 -10
  75. package/src/UserContext.res +2 -2
  76. package/src/UserContext.res.mjs +2 -1
  77. package/src/Utils.res +0 -4
  78. package/src/Utils.res.mjs +1 -6
  79. package/src/bindings/ClickHouse.res +20 -2
  80. package/src/bindings/ClickHouse.res.mjs +25 -14
  81. package/src/db/EntityFilter.res +0 -4
  82. package/src/db/EntityFilter.res.mjs +1 -8
  83. package/src/db/EntityHistory.res +1 -1
  84. package/src/db/IndexCatalog.res +248 -0
  85. package/src/db/IndexCatalog.res.mjs +222 -0
  86. package/src/db/IndexDefinition.res +131 -0
  87. package/src/db/IndexDefinition.res.mjs +138 -0
  88. package/src/db/IndexManager.res +145 -0
  89. package/src/db/IndexManager.res.mjs +130 -0
  90. package/src/db/InternalTable.res +54 -23
  91. package/src/db/InternalTable.res.mjs +38 -23
  92. package/src/db/Table.res +24 -14
  93. package/src/db/Table.res.mjs +21 -16
  94. package/src/sources/AddressSet.res +5 -4
  95. package/src/sources/AddressStore.res +25 -14
  96. package/src/sources/AddressStore.res.mjs +10 -12
  97. package/src/sources/Evm.res +2 -2
  98. package/src/sources/Evm.res.mjs +1 -1
  99. package/src/sources/EvmChain.res +3 -3
  100. package/src/sources/EvmChain.res.mjs +3 -3
  101. package/src/sources/EvmHyperSyncSource.res +7 -7
  102. package/src/sources/EvmHyperSyncSource.res.mjs +6 -6
  103. package/src/sources/Fuel.res +2 -2
  104. package/src/sources/Fuel.res.mjs +1 -1
  105. package/src/sources/FuelHyperSyncClient.res +3 -0
  106. package/src/sources/FuelHyperSyncClient.res.mjs +1 -0
  107. package/src/sources/FuelHyperSyncSource.res +5 -7
  108. package/src/sources/FuelHyperSyncSource.res.mjs +5 -5
  109. package/src/sources/HyperSync.resi +2 -2
  110. package/src/sources/HyperSyncClient.res +5 -0
  111. package/src/sources/HyperSyncClient.res.mjs +1 -0
  112. package/src/sources/RpcSource.res +13 -14
  113. package/src/sources/RpcSource.res.mjs +13 -12
  114. package/src/sources/SimulateSource.res +42 -15
  115. package/src/sources/SimulateSource.res.mjs +27 -9
  116. package/src/sources/Source.res +1 -5
  117. package/src/sources/SourceManager.res +12 -12
  118. package/src/sources/SourceManager.res.mjs +11 -10
  119. package/src/sources/SourceManager.resi +2 -2
  120. package/src/sources/Svm.res +4 -5
  121. package/src/sources/Svm.res.mjs +5 -4
  122. package/src/sources/SvmHyperSyncClient.res +3 -0
  123. package/src/sources/SvmHyperSyncClient.res.mjs +1 -0
  124. package/src/sources/SvmHyperSyncSource.res +4 -4
  125. package/src/sources/SvmHyperSyncSource.res.mjs +3 -3
  126. package/src/tui/Tui.res +1 -1
  127. package/src/tui/Tui.res.mjs +2 -1
  128. package/src/tui/components/CustomHooks.res +5 -4
  129. package/src/tui/components/CustomHooks.res.mjs +4 -2
@@ -43,7 +43,7 @@ let parseBlockInfo = (json: JSON.t): blockInfo => {
43
43
  let getKnownRawBlockWithBackoff = async (
44
44
  ~client,
45
45
  ~sourceName,
46
- ~chain,
46
+ ~chainId,
47
47
  ~blockNumber,
48
48
  ~backoffMsOnFailure,
49
49
  ~recordRequest: (~method: string, ~seconds: float) => unit,
@@ -60,7 +60,7 @@ let getKnownRawBlockWithBackoff = async (
60
60
  "err": err->Utils.prettifyExn,
61
61
  "msg": `Issue while running fetching batch of events from the RPC. Will wait ${currentBackoff.contents->Int.toString}ms and try again.`,
62
62
  "source": sourceName,
63
- "chainId": chain->ChainMap.Chain.toChainId,
63
+ "chainId": chainId,
64
64
  "type": "EXPONENTIAL_BACKOFF",
65
65
  })
66
66
  await Time.resolvePromiseAfterDelay(~delayMilliseconds=currentBackoff.contents)
@@ -613,7 +613,7 @@ type options = {
613
613
  sourceFor: Source.sourceFor,
614
614
  syncConfig: Config.sourceSync,
615
615
  url: string,
616
- chain: ChainMap.Chain.t,
616
+ chainId: ChainId.t,
617
617
  // The chain's registrations, indexed by their sequential `index`.
618
618
  onEventRegistrations: array<Internal.evmOnEventRegistration>,
619
619
  lowercaseAddresses: bool,
@@ -628,7 +628,7 @@ let make = (
628
628
  sourceFor,
629
629
  syncConfig,
630
630
  url,
631
- chain,
631
+ chainId,
632
632
  onEventRegistrations,
633
633
  lowercaseAddresses,
634
634
  addressStore,
@@ -636,11 +636,10 @@ let make = (
636
636
  ?headers,
637
637
  }: options,
638
638
  ): t => {
639
- let chainId = chain->ChainMap.Chain.toChainId
640
639
  let urlHost = switch Utils.Url.getHostFromUrl(url) {
641
640
  | None =>
642
641
  JsError.throwWithMessage(
643
- `The RPC url for chain ${chainId->Int.toString} is in incorrect format. The RPC url needs to start with either http:// or https://`,
642
+ `The RPC url for chain ${chainId->ChainId.toString} is in incorrect format. The RPC url needs to start with either http:// or https://`,
644
643
  )
645
644
  | Some(host) => host
646
645
  }
@@ -694,7 +693,7 @@ let make = (
694
693
  "msg": `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ${(am._retryDelayMillis / 1000)
695
694
  ->Int.toString} seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
696
695
  "source": name,
697
- "chainId": chain->ChainMap.Chain.toChainId,
696
+ "chainId": chainId,
698
697
  "metadata": {
699
698
  {
700
699
  "asyncTaskName": "transactionLoader: fetching transaction data - `getTransaction` rpc call",
@@ -711,7 +710,7 @@ let make = (
711
710
  getKnownRawBlockWithBackoff(
712
711
  ~client,
713
712
  ~sourceName=name,
714
- ~chain,
713
+ ~chainId,
715
714
  ~backoffMsOnFailure=1000,
716
715
  ~blockNumber,
717
716
  ~recordRequest,
@@ -723,7 +722,7 @@ let make = (
723
722
  "msg": `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ${(am._retryDelayMillis / 1000)
724
723
  ->Int.toString} seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
725
724
  "source": name,
726
- "chainId": chain->ChainMap.Chain.toChainId,
725
+ "chainId": chainId,
727
726
  "metadata": {
728
727
  {
729
728
  "asyncTaskName": "blockLoader: fetching block data - `getBlock` rpc call",
@@ -754,7 +753,7 @@ let make = (
754
753
  "msg": `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ${(am._retryDelayMillis / 1000)
755
754
  ->Int.toString} seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
756
755
  "source": name,
757
- "chainId": chain->ChainMap.Chain.toChainId,
756
+ "chainId": chainId,
758
757
  "metadata": {
759
758
  {
760
759
  "asyncTaskName": "receiptLoader: fetching transaction receipt - `getTransactionReceipt` rpc call",
@@ -926,13 +925,13 @@ let make = (
926
925
  Internal.Event({
927
926
  onEventRegistration: (onEventRegistration :> Internal.onEventRegistration),
928
927
  blockNumber: block->getBlockNumber,
929
- chain,
928
+ chainId,
930
929
  logIndex: log.logIndex,
931
930
  transactionIndex: log.transactionIndex,
932
931
  payload: {
933
932
  contractName: eventConfig.contractName,
934
933
  eventName: eventConfig.name,
935
- chainId: chain->ChainMap.Chain.toChainId,
934
+ chainId: chainId,
936
935
  params: decoded,
937
936
  block,
938
937
  transaction,
@@ -1024,13 +1023,13 @@ let make = (
1024
1023
 
1025
1024
  let createHeightSubscription =
1026
1025
  ws->Option.map(wsUrl =>
1027
- (~onHeight) => RpcWebSocketHeightStream.subscribe(~wsUrl, ~chainId, ~onHeight)
1026
+ (~onHeight) => RpcWebSocketHeightStream.subscribe(~wsUrl, ~chainId=chainId, ~onHeight)
1028
1027
  )
1029
1028
 
1030
1029
  {
1031
1030
  name,
1032
1031
  sourceFor,
1033
- chain,
1032
+ chainId,
1034
1033
  poweredByHyperSync: false,
1035
1034
  pollingInterval: syncConfig.pollingInterval,
1036
1035
  getBlockHashes,
@@ -6,6 +6,7 @@ import * as Time from "../Time.res.mjs";
6
6
  import * as Utils from "../Utils.res.mjs";
7
7
  import * as Source from "./Source.res.mjs";
8
8
  import * as Address from "../Address.res.mjs";
9
+ import * as ChainId from "../ChainId.res.mjs";
9
10
  import * as Logging from "../Logging.res.mjs";
10
11
  import * as Internal from "../Internal.res.mjs";
11
12
  import * as LazyLoader from "../LazyLoader.res.mjs";
@@ -44,7 +45,7 @@ function parseBlockInfo(json) {
44
45
  };
45
46
  }
46
47
 
47
- async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumber, backoffMsOnFailure, recordRequest) {
48
+ async function getKnownRawBlockWithBackoff(client, sourceName, chainId, blockNumber, backoffMsOnFailure, recordRequest) {
48
49
  let currentBackoff = backoffMsOnFailure;
49
50
  let result;
50
51
  while (Stdlib_Option.isNone(result)) {
@@ -61,7 +62,7 @@ async function getKnownRawBlockWithBackoff(client, sourceName, chain, blockNumbe
61
62
  err: Utils.prettifyExn(err),
62
63
  msg: `Issue while running fetching batch of events from the RPC. Will wait ` + currentBackoff.toString() + `ms and try again.`,
63
64
  source: sourceName,
64
- chainId: chain,
65
+ chainId: chainId,
65
66
  type: "EXPONENTIAL_BACKOFF"
66
67
  });
67
68
  await Time.resolvePromiseAfterDelay(currentBackoff);
@@ -727,11 +728,11 @@ function make(param) {
727
728
  let headers = param.headers;
728
729
  let lowercaseAddresses = param.lowercaseAddresses;
729
730
  let onEventRegistrations = param.onEventRegistrations;
730
- let chain = param.chain;
731
+ let chainId = param.chainId;
731
732
  let url = param.url;
732
733
  let syncConfig = param.syncConfig;
733
734
  let host = Utils.Url.getHostFromUrl(url);
734
- let urlHost = host !== undefined ? host : Stdlib_JsError.throwWithMessage(`The RPC url for chain ` + chain.toString() + ` is in incorrect format. The RPC url needs to start with either http:// or https://`);
735
+ let urlHost = host !== undefined ? host : Stdlib_JsError.throwWithMessage(`The RPC url for chain ` + ChainId.toString(chainId) + ` is in incorrect format. The RPC url needs to start with either http:// or https://`);
735
736
  let name = `RPC (` + urlHost + `)`;
736
737
  let client = Rpc.makeClient(url, headers);
737
738
  let rpcClient = EvmRpcClient.make(url, !lowercaseAddresses, syncConfig, undefined, headers, HyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations), param.addressStore);
@@ -757,17 +758,17 @@ function make(param) {
757
758
  err: Utils.prettifyExn(exn),
758
759
  msg: `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ` + (am._retryDelayMillis / 1000 | 0).toString() + ` seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
759
760
  source: name,
760
- chainId: chain,
761
+ chainId: chainId,
761
762
  metadata: {
762
763
  asyncTaskName: "transactionLoader: fetching transaction data - `getTransaction` rpc call",
763
764
  suggestedFix: "This likely means the RPC url you are using is not responding correctly. Please try another RPC endipoint."
764
765
  }
765
766
  }), undefined, undefined, undefined, undefined);
766
- let makeBlockLoader = () => LazyLoader.make(blockNumber => getKnownRawBlockWithBackoff(client, name, chain, blockNumber, 1000, recordRequest), (am, exn) => Logging.error({
767
+ let makeBlockLoader = () => LazyLoader.make(blockNumber => getKnownRawBlockWithBackoff(client, name, chainId, blockNumber, 1000, recordRequest), (am, exn) => Logging.error({
767
768
  err: Utils.prettifyExn(exn),
768
769
  msg: `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ` + (am._retryDelayMillis / 1000 | 0).toString() + ` seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
769
770
  source: name,
770
- chainId: chain,
771
+ chainId: chainId,
771
772
  metadata: {
772
773
  asyncTaskName: "blockLoader: fetching block data - `getBlock` rpc call",
773
774
  suggestedFix: "This likely means the RPC url you are using is not responding correctly. Please try another RPC endipoint."
@@ -783,7 +784,7 @@ function make(param) {
783
784
  err: Utils.prettifyExn(exn),
784
785
  msg: `Top level promise timeout reached. Please review other errors or warnings in the code. This function will retry in ` + (am._retryDelayMillis / 1000 | 0).toString() + ` seconds. It is highly likely that your indexer isn't syncing on one or more chains currently. Also take a look at the "suggestedFix" in the metadata of this command`,
785
786
  source: name,
786
- chainId: chain,
787
+ chainId: chainId,
787
788
  metadata: {
788
789
  asyncTaskName: "receiptLoader: fetching transaction receipt - `getTransactionReceipt` rpc call",
789
790
  suggestedFix: "This likely means the RPC url you are using is not responding correctly. Please try another RPC endipoint."
@@ -924,7 +925,7 @@ function make(param) {
924
925
  return {
925
926
  kind: 0,
926
927
  onEventRegistration: onEventRegistration,
927
- chain: chain,
928
+ chainId: chainId,
928
929
  blockNumber: block.number,
929
930
  logIndex: log.logIndex,
930
931
  transactionIndex: log.transactionIndex,
@@ -932,7 +933,7 @@ function make(param) {
932
933
  contractName: eventConfig.contractName,
933
934
  eventName: eventConfig.name,
934
935
  params: decoded,
935
- chainId: chain,
936
+ chainId: chainId,
936
937
  srcAddress: log.address,
937
938
  logIndex: log.logIndex,
938
939
  transaction: Primitive_option.some(match[1]),
@@ -1011,11 +1012,11 @@ function make(param) {
1011
1012
  },
1012
1013
  requestStats: drainRequestStats()
1013
1014
  }));
1014
- let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => (onHeight => RpcWebSocketHeightStream.subscribe(wsUrl, chain, onHeight)));
1015
+ let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => (onHeight => RpcWebSocketHeightStream.subscribe(wsUrl, chainId, onHeight)));
1015
1016
  return {
1016
1017
  name: name,
1017
1018
  sourceFor: param.sourceFor,
1018
- chain: chain,
1019
+ chainId: chainId,
1019
1020
  poweredByHyperSync: false,
1020
1021
  pollingInterval: syncConfig.pollingInterval,
1021
1022
  getBlockHashes: getBlockHashes,
@@ -1,11 +1,15 @@
1
- let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain.t): Source.t => {
1
+ let make = (
2
+ ~items: array<Internal.item>,
3
+ ~endBlock: int,
4
+ ~chainId: ChainId.t,
5
+ ~addressStore: AddressStore.t,
6
+ ): Source.t => {
2
7
  let reportedHeight = max(endBlock, 1)
3
8
 
4
9
  {
5
10
  name: "SimulateSource",
6
- simulateItems: items,
7
11
  sourceFor: Sync,
8
- chain,
12
+ chainId,
9
13
  poweredByHyperSync: false,
10
14
  pollingInterval: 0,
11
15
  getBlockHashes: (~blockNumbers as _, ~logger as _) => {
@@ -27,8 +31,9 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
27
31
  ~logger as _,
28
32
  ) => {
29
33
  // Mirror a real backend: return only the items this query would match —
30
- // in the block range, part of the selection, and passing the same address
31
- // gates a real source applies natively while routing (the emitter must be
34
+ // in the block range, part of the selection, at or after the
35
+ // registration's own start block, and passing the same address gates a
36
+ // real source applies natively while routing (the emitter must be
32
37
  // registered for the event's contract at or before the item's block, and
33
38
  // any address-valued param filter must hold). Overlapping queries may
34
39
  // return the same item more than once; the buffer dedups it.
@@ -36,27 +41,49 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
36
41
  | Some(toBlock) => toBlock
37
42
  | None => reportedHeight
38
43
  }
39
- let selectionEventIds = Utils.Set.make()
44
+ // By registration index, not `eventConfig.id`: two registrations of the
45
+ // same event are independent and may sit in different partitions, so
46
+ // matching on the shared event id would let a sibling's items leak into
47
+ // this query.
48
+ let selectionRegistrationIndexes = Utils.Set.make()
40
49
  selection.onEventRegistrations->Array.forEach(reg =>
41
- selectionEventIds->Utils.Set.add(reg.eventConfig.id)->ignore
50
+ selectionRegistrationIndexes->Utils.Set.add(reg.index)->ignore
42
51
  )
43
52
 
53
+ // A client-filtered contract is queried address-free, so this partition
54
+ // holds none of its addresses and only the chain-wide store can answer
55
+ // for it — exactly the fallback every real source's router makes.
56
+ let isAddressAllowed = (address, ~contractName, ~blockNumber) =>
57
+ switch selection.clientFilteredContracts {
58
+ | Some(contractNames) if contractNames->Array.includes(contractName) =>
59
+ addressStore->AddressStore.isIndexedAt(address, contractName, blockNumber)
60
+ | _ => addressSet->AddressSet.containsAt(address, contractName, blockNumber)
61
+ }
62
+
63
+ // The registration's own start block, which the contract-wide address gate
64
+ // can't express. Every native router applies it while routing.
65
+ let hasStarted = (onEventRegistration: Internal.onEventRegistration, ~blockNumber) =>
66
+ switch onEventRegistration.startBlock {
67
+ | Some(startBlock) => blockNumber >= startBlock
68
+ | None => true
69
+ }
70
+
44
71
  let parsedQueueItems = items->Array.filter(item => {
45
72
  let eventItem = item->Internal.castUnsafeEventItem
46
73
  let {blockNumber, onEventRegistration} = eventItem
47
74
  if blockNumber < fromBlock || blockNumber > toBlockQueried {
48
75
  false
49
- } else if !(selectionEventIds->Utils.Set.has(onEventRegistration.eventConfig.id)) {
76
+ } else if !(selectionRegistrationIndexes->Utils.Set.has(onEventRegistration.index)) {
77
+ false
78
+ } else if !(onEventRegistration->hasStarted(~blockNumber)) {
50
79
  false
51
80
  } else {
52
81
  let contractName = onEventRegistration.eventConfig.contractName
53
82
  let emitterAllowed =
54
83
  onEventRegistration.isWildcard ||
55
- addressSet->AddressSet.has(
56
- eventItem.payload->Internal.getPayloadSrcAddress,
57
- contractName,
58
- blockNumber,
59
- )
84
+ eventItem.payload
85
+ ->Internal.getPayloadSrcAddress
86
+ ->isAddressAllowed(~contractName, ~blockNumber)
60
87
  emitterAllowed &&
61
88
  switch onEventRegistration.addressFilterParamGroups {
62
89
  | None
@@ -64,8 +91,8 @@ let make = (~items: array<Internal.item>, ~endBlock: int, ~chain: ChainMap.Chain
64
91
  | Some(groups) =>
65
92
  let params = eventItem.payload->Internal.getPayloadAddressParams
66
93
  groups->Array.some(group =>
67
- group->Array.every(name =>
68
- addressSet->AddressSet.has(params->Dict.getUnsafe(name), contractName, blockNumber)
94
+ group->Array.every(
95
+ name => params->Dict.getUnsafe(name)->isAddressAllowed(~contractName, ~blockNumber),
69
96
  )
70
97
  )
71
98
  }
@@ -2,12 +2,12 @@
2
2
 
3
3
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
4
4
 
5
- function make(items, endBlock, chain) {
5
+ function make(items, endBlock, chainId, addressStore) {
6
6
  let reportedHeight = Primitive_int.max(endBlock, 1);
7
7
  return {
8
8
  name: "SimulateSource",
9
9
  sourceFor: "Sync",
10
- chain: chain,
10
+ chainId: chainId,
11
11
  poweredByHyperSync: false,
12
12
  pollingInterval: 0,
13
13
  getBlockHashes: (param, param$1) => Promise.resolve({
@@ -23,21 +23,40 @@ function make(items, endBlock, chain) {
23
23
  }),
24
24
  getItemsOrThrow: (fromBlock, toBlock, addressSet, param, param$1, selection, param$2, param$3, param$4) => {
25
25
  let toBlockQueried = toBlock !== undefined ? toBlock : reportedHeight;
26
- let selectionEventIds = new Set();
26
+ let selectionRegistrationIndexes = new Set();
27
27
  selection.onEventRegistrations.forEach(reg => {
28
- selectionEventIds.add(reg.eventConfig.id);
28
+ selectionRegistrationIndexes.add(reg.index);
29
29
  });
30
+ let isAddressAllowed = (address, contractName, blockNumber) => {
31
+ let contractNames = selection.clientFilteredContracts;
32
+ if (contractNames !== undefined && contractNames.includes(contractName)) {
33
+ return addressStore.isIndexedAt(address, contractName, blockNumber);
34
+ } else {
35
+ return addressSet.containsAt(address, contractName, blockNumber);
36
+ }
37
+ };
38
+ let hasStarted = (onEventRegistration, blockNumber) => {
39
+ let startBlock = onEventRegistration.startBlock;
40
+ if (startBlock !== undefined) {
41
+ return blockNumber >= startBlock;
42
+ } else {
43
+ return true;
44
+ }
45
+ };
30
46
  let parsedQueueItems = items.filter(item => {
31
47
  let blockNumber = item.blockNumber;
32
48
  if (blockNumber < fromBlock || blockNumber > toBlockQueried) {
33
49
  return false;
34
50
  }
35
51
  let onEventRegistration = item.onEventRegistration;
36
- if (!selectionEventIds.has(onEventRegistration.eventConfig.id)) {
52
+ if (!selectionRegistrationIndexes.has(onEventRegistration.index)) {
53
+ return false;
54
+ }
55
+ if (!hasStarted(onEventRegistration, blockNumber)) {
37
56
  return false;
38
57
  }
39
58
  let contractName = onEventRegistration.eventConfig.contractName;
40
- let emitterAllowed = onEventRegistration.isWildcard || addressSet.has(item.payload.srcAddress, contractName, blockNumber);
59
+ let emitterAllowed = onEventRegistration.isWildcard || isAddressAllowed(item.payload.srcAddress, contractName, blockNumber);
41
60
  if (!emitterAllowed) {
42
61
  return false;
43
62
  }
@@ -49,7 +68,7 @@ function make(items, endBlock, chain) {
49
68
  return true;
50
69
  }
51
70
  let params = item.payload.params;
52
- return groups.some(group => group.every(name => addressSet.has(params[name], contractName, blockNumber)));
71
+ return groups.some(group => group.every(name => isAddressAllowed(params[name], contractName, blockNumber)));
53
72
  });
54
73
  return Promise.resolve({
55
74
  knownHeight: reportedHeight,
@@ -65,8 +84,7 @@ function make(items, endBlock, chain) {
65
84
  },
66
85
  requestStats: []
67
86
  });
68
- },
69
- simulateItems: items
87
+ }
70
88
  };
71
89
  }
72
90
 
@@ -64,7 +64,7 @@ type sourceFor = Sync | Fallback | Realtime
64
64
  type t = {
65
65
  name: string,
66
66
  sourceFor: sourceFor,
67
- chain: ChainMap.Chain.t,
67
+ chainId: ChainId.t,
68
68
  poweredByHyperSync: bool,
69
69
  /* Frequency (in ms) used when polling for new events on this network. */
70
70
  pollingInterval: int,
@@ -95,8 +95,4 @@ type t = {
95
95
  // Invoked by SourceManager once a rollback target is known so the source can
96
96
  // drop any state that may now point at an orphaned chain (e.g. RPC block cache).
97
97
  onReorg?: (~rollbackTargetBlock: int) => unit,
98
- // Present only on the simulate source: the items a test fed in. The chain
99
- // tracks which of these never reach a handler so the run can report dead
100
- // simulate inputs on completion.
101
- simulateItems?: array<Internal.item>,
102
98
  }
@@ -32,7 +32,7 @@ let recordRequestStats = (sourceState: sourceState, requestStats: array<Source.r
32
32
  // inline into the /metrics response.
33
33
  type requestStatSample = {
34
34
  sourceName: string,
35
- chainId: int,
35
+ chainId: ChainId.t,
36
36
  method: string,
37
37
  count: int,
38
38
  seconds: float,
@@ -81,7 +81,7 @@ let getActiveSource = sourceManager => sourceManager.activeSource
81
81
  let getRequestStatSamples = (sourceManager: t): array<requestStatSample> => {
82
82
  let samples = []
83
83
  sourceManager.sourcesState->Array.forEach(sourceState => {
84
- let chainId = sourceState.source.chain->ChainMap.Chain.toChainId
84
+ let chainId = sourceState.source.chainId
85
85
  sourceState.requestStats->Utils.Dict.forEachWithKey((agg, method) => {
86
86
  samples
87
87
  ->Array.push({
@@ -101,7 +101,7 @@ let getRequestStatSamples = (sourceManager: t): array<requestStatSample> => {
101
101
  // observed height yet are skipped.
102
102
  type sourceHeightSample = {
103
103
  sourceName: string,
104
- chainId: int,
104
+ chainId: ChainId.t,
105
105
  height: int,
106
106
  }
107
107
 
@@ -111,7 +111,7 @@ let getSourceHeightSamples = (sourceManager: t): array<sourceHeightSample> => {
111
111
  if sourceState.knownHeight > 0 {
112
112
  samples->Array.push({
113
113
  sourceName: sourceState.source.name,
114
- chainId: sourceState.source.chain->ChainMap.Chain.toChainId,
114
+ chainId: sourceState.source.chainId,
115
115
  height: sourceState.knownHeight,
116
116
  })
117
117
  }
@@ -425,7 +425,7 @@ let getSourceNewHeight = async (
425
425
  logger->Logging.childTrace({
426
426
  "msg": "onHeight subscription stale, switching to polling fallback",
427
427
  "source": source.name,
428
- "chainId": source.chain->ChainMap.Chain.toChainId,
428
+ "chainId": source.chainId,
429
429
  })
430
430
  let h = ref(initialHeight)
431
431
  while h.contents <= knownHeight && !(newHeight.contents > initialHeight) {
@@ -585,7 +585,7 @@ let waitForNewBlock = async (sourceManager: t, ~knownHeight, ~isRealtime, ~reduc
585
585
 
586
586
  let logger = Logging.createChild(
587
587
  ~params={
588
- "chainId": sourceManager.activeSource.chain->ChainMap.Chain.toChainId,
588
+ "chainId": sourceManager.activeSource.chainId,
589
589
  "knownHeight": knownHeight,
590
590
  },
591
591
  )
@@ -725,7 +725,7 @@ let executeQuery = async (
725
725
  | Some(s) =>
726
726
  if s.source !== sourceManager.activeSource {
727
727
  let logger = Logging.createChild(
728
- ~params={"chainId": sourceManager.activeSource.chain->ChainMap.Chain.toChainId},
728
+ ~params={"chainId": sourceManager.activeSource.chainId},
729
729
  )
730
730
  logger->Logging.childInfo({
731
731
  "msg": "Switching data-source",
@@ -737,7 +737,7 @@ let executeQuery = async (
737
737
  s
738
738
  | None =>
739
739
  let logger = Logging.createChild(
740
- ~params={"chainId": sourceManager.activeSource.chain->ChainMap.Chain.toChainId},
740
+ ~params={"chainId": sourceManager.activeSource.chainId},
741
741
  )
742
742
  %raw(`null`)->ErrorHandling.mkLogAndRaise(~logger, ~msg=noSourcesError)
743
743
  }
@@ -748,7 +748,7 @@ let executeQuery = async (
748
748
 
749
749
  let logger = Logging.createChild(
750
750
  ~params={
751
- "chainId": source.chain->ChainMap.Chain.toChainId,
751
+ "chainId": source.chainId,
752
752
  "logType": "Block Range Query",
753
753
  "partitionId": query.partitionId,
754
754
  "source": source.name,
@@ -766,7 +766,7 @@ let executeQuery = async (
766
766
  ~addressSet=query.addresses,
767
767
  ~partitionId=query.partitionId,
768
768
  ~knownHeight,
769
- ~selection=query.selection,
769
+ ~selection=query.selection->FetchState.narrowSelectionToRange(~toBlock),
770
770
  ~itemsTarget=query.itemsTarget,
771
771
  ~retry,
772
772
  ~logger,
@@ -896,7 +896,7 @@ let getBlockHashes = async (sourceManager: t, ~blockNumbers: array<int>, ~isReal
896
896
  | Some(s) => s
897
897
  | None =>
898
898
  let logger = Logging.createChild(
899
- ~params={"chainId": sourceManager.activeSource.chain->ChainMap.Chain.toChainId},
899
+ ~params={"chainId": sourceManager.activeSource.chainId},
900
900
  )
901
901
  %raw(`null`)->ErrorHandling.mkLogAndRaise(
902
902
  ~logger,
@@ -909,7 +909,7 @@ let getBlockHashes = async (sourceManager: t, ~blockNumbers: array<int>, ~isReal
909
909
 
910
910
  let logger = Logging.createChild(
911
911
  ~params={
912
- "chainId": source.chain->ChainMap.Chain.toChainId,
912
+ "chainId": source.chainId,
913
913
  "logType": "Block Hash Query",
914
914
  "source": source.name,
915
915
  "retry": retry,
@@ -3,6 +3,7 @@
3
3
  import * as Utils from "../Utils.res.mjs";
4
4
  import * as Source from "./Source.res.mjs";
5
5
  import * as Logging from "../Logging.res.mjs";
6
+ import * as FetchState from "../FetchState.res.mjs";
6
7
  import * as Performance from "../bindings/Performance.res.mjs";
7
8
  import * as ErrorHandling from "../ErrorHandling.res.mjs";
8
9
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
@@ -36,7 +37,7 @@ function getActiveSource(sourceManager) {
36
37
  function getRequestStatSamples(sourceManager) {
37
38
  let samples = [];
38
39
  sourceManager.sourcesState.forEach(sourceState => {
39
- let chainId = sourceState.source.chain;
40
+ let chainId = sourceState.source.chainId;
40
41
  Utils.Dict.forEachWithKey(sourceState.requestStats, (agg, method) => {
41
42
  samples.push({
42
43
  sourceName: sourceState.source.name,
@@ -56,7 +57,7 @@ function getSourceHeightSamples(sourceManager) {
56
57
  if (sourceState.knownHeight > 0) {
57
58
  samples.push({
58
59
  sourceName: sourceState.source.name,
59
- chainId: sourceState.source.chain,
60
+ chainId: sourceState.source.chainId,
60
61
  height: sourceState.knownHeight
61
62
  });
62
63
  return;
@@ -350,7 +351,7 @@ async function getSourceNewHeight(sourceManager, sourceState, knownHeight, stall
350
351
  Logging.childTrace(logger, {
351
352
  msg: "onHeight subscription stale, switching to polling fallback",
352
353
  source: source.name,
353
- chainId: source.chain
354
+ chainId: source.chainId
354
355
  });
355
356
  let h = initialHeight;
356
357
  while (h <= knownHeight && newHeight.contents <= initialHeight) {
@@ -506,7 +507,7 @@ function getNextSource(sourceManager, isRealtime, excludedSources) {
506
507
  async function waitForNewBlock(sourceManager, knownHeight, isRealtime, reducedPolling) {
507
508
  let sourcesState = sourceManager.sourcesState;
508
509
  let logger = Logging.createChild({
509
- chainId: sourceManager.activeSource.chain,
510
+ chainId: sourceManager.activeSource.chainId,
510
511
  knownHeight: knownHeight
511
512
  });
512
513
  if (!sourceManager.waitingLogged) {
@@ -569,7 +570,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
569
570
  if (s !== undefined) {
570
571
  if (s.source !== sourceManager.activeSource) {
571
572
  let logger = Logging.createChild({
572
- chainId: sourceManager.activeSource.chain
573
+ chainId: sourceManager.activeSource.chainId
573
574
  });
574
575
  Logging.childInfo(logger, {
575
576
  msg: "Switching data-source",
@@ -581,7 +582,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
581
582
  sourceState = s;
582
583
  } else {
583
584
  let logger$1 = Logging.createChild({
584
- chainId: sourceManager.activeSource.chain
585
+ chainId: sourceManager.activeSource.chainId
585
586
  });
586
587
  sourceState = ErrorHandling.mkLogAndRaise(logger$1, "The indexer doesn't have data-sources which can continue fetching. Please, check the error logs or reach out to the Envio team.", null);
587
588
  }
@@ -590,7 +591,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
590
591
  let toBlock = toBlockRef;
591
592
  let retry = retryRef;
592
593
  let logger$2 = Logging.createChild({
593
- chainId: source.chain,
594
+ chainId: source.chainId,
594
595
  logType: "Block Range Query",
595
596
  partitionId: query.partitionId,
596
597
  source: source.name,
@@ -600,7 +601,7 @@ async function executeQuery(sourceManager, query, knownHeight, isRealtime) {
600
601
  retry: retry
601
602
  });
602
603
  try {
603
- let response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addresses, knownHeight, query.partitionId, query.selection, query.itemsTarget, retry, logger$2);
604
+ let response = await source.getItemsOrThrow(query.fromBlock, toBlock, query.addresses, knownHeight, query.partitionId, FetchState.narrowSelectionToRange(query.selection, toBlock), query.itemsTarget, retry, logger$2);
604
605
  recordRequestStats(sourceState, response.requestStats);
605
606
  sourceState.lastFailedAt = undefined;
606
607
  if (response.knownHeight > sourceState.knownHeight) {
@@ -725,7 +726,7 @@ async function getBlockHashes(sourceManager, blockNumbers, isRealtime) {
725
726
  sourceState = s;
726
727
  } else {
727
728
  let logger = Logging.createChild({
728
- chainId: sourceManager.activeSource.chain
729
+ chainId: sourceManager.activeSource.chainId
729
730
  });
730
731
  sourceState = ErrorHandling.mkLogAndRaise(logger, "No data-sources available for fetching block hashes.", null);
731
732
  }
@@ -733,7 +734,7 @@ async function getBlockHashes(sourceManager, blockNumbers, isRealtime) {
733
734
  let source = sourceState.source;
734
735
  let retry = retryRef;
735
736
  let logger$1 = Logging.createChild({
736
- chainId: source.chain,
737
+ chainId: source.chainId,
737
738
  logType: "Block Hash Query",
738
739
  source: source.name,
739
740
  retry: retry
@@ -23,7 +23,7 @@ let getActiveSource: t => Source.t
23
23
 
24
24
  type requestStatSample = {
25
25
  sourceName: string,
26
- chainId: int,
26
+ chainId: ChainId.t,
27
27
  method: string,
28
28
  count: int,
29
29
  seconds: float,
@@ -33,7 +33,7 @@ let getRequestStatSamples: t => array<requestStatSample>
33
33
 
34
34
  type sourceHeightSample = {
35
35
  sourceName: string,
36
- chainId: int,
36
+ chainId: ChainId.t,
37
37
  height: int,
38
38
  }
39
39
 
@@ -50,7 +50,7 @@ let make = (~logger: Pino.t): Ecosystem.t => {
50
50
  ~params={
51
51
  "program": eventItem.onEventRegistration.eventConfig.contractName,
52
52
  "instruction": eventItem.onEventRegistration.eventConfig.name,
53
- "chainId": eventItem.chain->ChainMap.Chain.toChainId,
53
+ "chainId": eventItem.chainId,
54
54
  "slot": eventItem.blockNumber,
55
55
  "programId": instruction.programId,
56
56
  },
@@ -70,14 +70,13 @@ module GetFinalizedSlot = {
70
70
  )
71
71
  }
72
72
 
73
- let makeRPCSource = (~chain, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): Source.t => {
73
+ let makeRPCSource = (~chainId, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): Source.t => {
74
74
  let client = Rest.client(rpc)
75
- let chainId = chain->ChainMap.Chain.toChainId
76
75
 
77
76
  let urlHost = switch Utils.Url.getHostFromUrl(rpc) {
78
77
  | None =>
79
78
  JsError.throwWithMessage(
80
- `The RPC url for chain ${chainId->Int.toString} is in incorrect format. The RPC url needs to start with either http:// or https://`,
79
+ `The RPC url for chain ${chainId->ChainId.toString} is in incorrect format. The RPC url needs to start with either http:// or https://`,
81
80
  )
82
81
  | Some(host) => host
83
82
  }
@@ -86,7 +85,7 @@ let makeRPCSource = (~chain, ~rpc: string, ~sourceFor: Source.sourceFor=Sync): S
86
85
  {
87
86
  name,
88
87
  sourceFor,
89
- chain,
88
+ chainId,
90
89
  poweredByHyperSync: false,
91
90
  pollingInterval: 10_000,
92
91
  getBlockHashes: (~blockNumbers as _, ~logger as _) =>