envio 3.2.1 → 3.3.0-alpha.1

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 (106) hide show
  1. package/package.json +6 -7
  2. package/src/Batch.res +12 -15
  3. package/src/Batch.res.mjs +4 -5
  4. package/src/BatchProcessing.res +199 -0
  5. package/src/BatchProcessing.res.mjs +125 -0
  6. package/src/ChainFetching.res +373 -0
  7. package/src/ChainFetching.res.mjs +206 -0
  8. package/src/ChainMetadata.res +27 -0
  9. package/src/ChainMetadata.res.mjs +27 -0
  10. package/src/ChainState.res +643 -0
  11. package/src/ChainState.res.mjs +476 -0
  12. package/src/ChainState.resi +87 -0
  13. package/src/Config.res +13 -4
  14. package/src/Config.res.mjs +8 -3
  15. package/src/ContractRegisterContext.res +106 -0
  16. package/src/ContractRegisterContext.res.mjs +76 -0
  17. package/src/Core.res +3 -0
  18. package/src/CrossChainState.res +294 -0
  19. package/src/CrossChainState.res.mjs +221 -0
  20. package/src/CrossChainState.resi +39 -0
  21. package/src/Ecosystem.res +58 -0
  22. package/src/Ecosystem.res.mjs +43 -1
  23. package/src/Env.res +0 -2
  24. package/src/Env.res.mjs +0 -3
  25. package/src/EventConfigBuilder.res +2 -2
  26. package/src/EventProcessing.res +60 -46
  27. package/src/EventProcessing.res.mjs +33 -32
  28. package/src/EventUtils.res +0 -4
  29. package/src/EventUtils.res.mjs +0 -4
  30. package/src/ExitOnCaughtUp.res +10 -0
  31. package/src/ExitOnCaughtUp.res.mjs +22 -0
  32. package/src/FetchState.res +205 -73
  33. package/src/FetchState.res.mjs +242 -103
  34. package/src/InMemoryStore.res +36 -451
  35. package/src/InMemoryStore.res.mjs +20 -369
  36. package/src/IndexerLoop.res +43 -0
  37. package/src/IndexerLoop.res.mjs +46 -0
  38. package/src/IndexerState.res +536 -0
  39. package/src/IndexerState.res.mjs +543 -0
  40. package/src/IndexerState.resi +128 -0
  41. package/src/Internal.res +29 -8
  42. package/src/LoadLayer.res +20 -18
  43. package/src/LoadLayer.res.mjs +14 -12
  44. package/src/LoadLayer.resi +6 -3
  45. package/src/Logging.res +11 -44
  46. package/src/Logging.res.mjs +10 -42
  47. package/src/Main.res +54 -79
  48. package/src/Main.res.mjs +44 -56
  49. package/src/PgStorage.res +8 -71
  50. package/src/PgStorage.res.mjs +3 -47
  51. package/src/Prometheus.res +1 -13
  52. package/src/Prometheus.res.mjs +84 -96
  53. package/src/PruneStaleHistory.res +45 -0
  54. package/src/PruneStaleHistory.res.mjs +46 -0
  55. package/src/RawEvent.res +73 -0
  56. package/src/RawEvent.res.mjs +51 -0
  57. package/src/Rollback.res +204 -0
  58. package/src/Rollback.res.mjs +118 -0
  59. package/src/SimulateItems.res +12 -10
  60. package/src/SimulateItems.res.mjs +1 -1
  61. package/src/UserContext.res +26 -114
  62. package/src/UserContext.res.mjs +15 -78
  63. package/src/Writing.res +242 -0
  64. package/src/Writing.res.mjs +215 -0
  65. package/src/db/InternalTable.res +14 -27
  66. package/src/sources/Evm.res +40 -1
  67. package/src/sources/Evm.res.mjs +94 -84
  68. package/src/sources/Fuel.res +40 -1
  69. package/src/sources/Fuel.res.mjs +36 -26
  70. package/src/sources/HyperFuel.res +41 -120
  71. package/src/sources/HyperFuel.res.mjs +42 -80
  72. package/src/sources/HyperFuel.resi +1 -24
  73. package/src/sources/HyperFuelClient.res +16 -297
  74. package/src/sources/HyperFuelClient.res.mjs +5 -4
  75. package/src/sources/HyperFuelSource.res +33 -8
  76. package/src/sources/HyperFuelSource.res.mjs +56 -10
  77. package/src/sources/HyperSyncSource.res +5 -3
  78. package/src/sources/HyperSyncSource.res.mjs +1 -1
  79. package/src/sources/RpcSource.res +2 -2
  80. package/src/sources/RpcSource.res.mjs +1 -1
  81. package/src/sources/SourceManager.res +14 -23
  82. package/src/sources/SourceManager.res.mjs +27 -29
  83. package/src/sources/SourceManager.resi +4 -2
  84. package/src/sources/Svm.res +18 -1
  85. package/src/sources/Svm.res.mjs +30 -22
  86. package/src/sources/SvmHyperSyncSource.res +1 -1
  87. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  88. package/src/tui/Tui.res +38 -36
  89. package/src/tui/Tui.res.mjs +51 -51
  90. package/src/ChainFetcher.res +0 -519
  91. package/src/ChainFetcher.res.mjs +0 -314
  92. package/src/ChainManager.res +0 -358
  93. package/src/ChainManager.res.mjs +0 -291
  94. package/src/Ctx.res +0 -6
  95. package/src/Ctx.res.mjs +0 -2
  96. package/src/GlobalState.res +0 -1056
  97. package/src/GlobalState.res.mjs +0 -1086
  98. package/src/GlobalStateManager.res +0 -57
  99. package/src/GlobalStateManager.res.mjs +0 -68
  100. package/src/GlobalStateManager.resi +0 -7
  101. package/src/Ports.res +0 -5
  102. package/src/Ports.res.mjs +0 -9
  103. package/src/adapters/MarkBatchProcessedAdapter.res +0 -5
  104. package/src/adapters/MarkBatchProcessedAdapter.res.mjs +0 -14
  105. package/src/sources/EnvioApiClient.res +0 -15
  106. package/src/sources/EnvioApiClient.res.mjs +0 -24
package/src/Main.res CHANGED
@@ -79,7 +79,7 @@ let blockRangeSchema: S.t<blockRange> = S.object(s => {
79
79
 
80
80
  let defaultBlockRange: blockRange = {_gte: None, _lte: None, _every: 1}
81
81
 
82
- let globalGsManagerRef: ref<option<GlobalStateManager.t>> = ref(None)
82
+ let indexerStateRef: ref<option<IndexerState.t>> = ref(None)
83
83
 
84
84
  // Persistence is set by Main.start before handler modules load, so that
85
85
  // the exported indexer value can lazily expose DB state (startBlock,
@@ -145,12 +145,12 @@ let buildChainsObject = (~config: Config.t) => {
145
145
  {
146
146
  enumerable: true,
147
147
  get: () => {
148
- switch globalGsManagerRef.contents {
149
- | Some(gsManager) => (gsManager->GlobalStateManager.getState).chainManager.isRealtime
150
- // Before the GlobalStateManager is available (eg during handler
148
+ switch indexerStateRef.contents {
149
+ | Some(state) => state->IndexerState.isRealtime
150
+ // Before the global state is available (eg during handler
151
151
  // module load after resume), derive from persistence: every chain
152
152
  // must have previously caught up to head or endBlock. Mirror the
153
- // ChainManager.makeFromDbState path: updateSyncTimeOnRestart wipes
153
+ // IndexerState.makeFromDbState path: updateSyncTimeOnRestart wipes
154
154
  // the saved timestamps so a restart re-enters backfill.
155
155
  | None if Env.updateSyncTimeOnRestart => false
156
156
  | None =>
@@ -179,12 +179,11 @@ let buildChainsObject = (~config: Config.t) => {
179
179
  {
180
180
  enumerable: true,
181
181
  get: () => {
182
- switch globalGsManagerRef.contents {
183
- | Some(gsManager) => {
184
- let state = gsManager->GlobalStateManager.getState
182
+ switch indexerStateRef.contents {
183
+ | Some(state) => {
185
184
  let chain = ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)
186
- let chainFetcher = state.chainManager.chainFetchers->ChainMap.get(chain)
187
- let indexingAddresses = chainFetcher.fetchState.indexingAddresses
185
+ let chainState = state->IndexerState.getChainState(~chain)
186
+ let indexingAddresses = (chainState->ChainState.fetchState).indexingAddresses
188
187
 
189
188
  // Collect all addresses for this contract name from indexingAddresses
190
189
  let addresses = []
@@ -197,7 +196,7 @@ let buildChainsObject = (~config: Config.t) => {
197
196
  }
198
197
  addresses
199
198
  }
200
- // Before the GlobalStateManager is available (eg during handler
199
+ // Before the global state is available (eg during handler
201
200
  // module load after resume), combine static addresses from config
202
201
  // with dynamic contracts persisted in the database.
203
202
  | None =>
@@ -586,7 +585,7 @@ let getGlobalIndexer = (): 'indexer => {
586
585
  Utils.Proxy.make(Utils.Object.createNullObject(), traps)->(Utils.magic: {..} => 'indexer)
587
586
  }
588
587
 
589
- let startServer = (~getState, ~ctx: Ctx.t, ~isDevelopmentMode: bool) => {
588
+ let startServer = (~getState, ~persistence: Persistence.t, ~isDevelopmentMode: bool) => {
590
589
  open Express
591
590
 
592
591
  let app = make()
@@ -629,7 +628,7 @@ let startServer = (~getState, ~ctx: Ctx.t, ~isDevelopmentMode: bool) => {
629
628
 
630
629
  app->post("/console/syncCache", (_req, res) => {
631
630
  if isDevelopmentMode {
632
- (ctx.persistence->Persistence.getInitializedStorageOrThrow).dumpEffectCache()
631
+ (persistence->Persistence.getInitializedStorageOrThrow).dumpEffectCache()
633
632
  ->Promise.thenResolve(_ => res->json(Boolean(true)))
634
633
  ->Promise.ignore
635
634
  } else {
@@ -757,112 +756,88 @@ let start = async (
757
756
  | Some(patchConfig) => patchConfig(config, registrations)
758
757
  | None => config
759
758
  }
760
- // The single fatal-error handler, shared by the store, ErrorExit, and the
761
- // manager's catch.
759
+ // The single fatal-error handler, invoked once via IndexerState.errorExit.
762
760
  let onError = (errHandler: ErrorHandling.t) => {
763
761
  errHandler->ErrorHandling.log
764
- NodeJs.process->NodeJs.exitWithCode(Failure)
765
- }
766
- let ctx = {
767
- Ctx.registrations,
768
- config,
769
- persistence,
770
- inMemoryStore: InMemoryStore.make(
771
- ~entities=persistence.allEntities,
772
- ~committedCheckpointId=(persistence->Persistence.getInitializedState).checkpointId,
773
- ~persistence,
774
- ~config,
775
- ~onError=exn => onError(exn->ErrorHandling.make(~msg="Failed writing batch to the database")),
776
- ),
762
+ if isTest {
763
+ // The TestIndexer runs the indexer in a worker thread and reads the
764
+ // failure off the worker 'error' event. Re-throw the original error
765
+ // outside the promise chain on the next tick so the test sees its real
766
+ // message instead of a generic non-zero exit code.
767
+ NodeJs.setImmediate(() => errHandler->ErrorHandling.raiseExn)
768
+ } else {
769
+ NodeJs.process->NodeJs.exitWithCode(Failure)
770
+ }
777
771
  }
778
-
779
772
  let envioVersion = Utils.EnvioPackage.value.version
780
773
  Prometheus.Info.set(~version=envioVersion)
781
774
  Prometheus.ProcessStartTimeSeconds.set()
782
- Prometheus.RollbackEnabled.set(~enabled=ctx.config.shouldRollbackOnReorg)
775
+ Prometheus.RollbackEnabled.set(~enabled=config.shouldRollbackOnReorg)
783
776
 
784
777
  if !isTest {
785
- startServer(~ctx, ~isDevelopmentMode, ~getState=() =>
786
- switch globalGsManagerRef.contents {
778
+ startServer(~persistence, ~isDevelopmentMode, ~getState=() =>
779
+ switch indexerStateRef.contents {
787
780
  | None => Initializing({})
788
- | Some(gsManager) => {
789
- let state = gsManager->GlobalStateManager.getState
781
+ | Some(state) => {
790
782
  let chains =
791
- state.chainManager.chainFetchers
792
- ->ChainMap.values
793
- ->Array.map(cf => {
794
- let {fetchState} = cf
783
+ state
784
+ ->IndexerState.chainStates
785
+ ->Dict.valuesToArray
786
+ ->Array.map(cs => {
787
+ let fetchState = cs->ChainState.fetchState
795
788
  let latestFetchedBlockNumber = Pervasives.max(
796
789
  FetchState.bufferBlockNumber(fetchState),
797
790
  0,
798
791
  )
799
792
  let knownHeight =
800
- cf->ChainFetcher.hasProcessedToEndblock
801
- ? cf.fetchState.endBlock->Option.getOr(cf.fetchState.knownHeight)
802
- : cf.fetchState.knownHeight
793
+ cs->ChainState.hasProcessedToEndblock
794
+ ? fetchState.endBlock->Option.getOr(fetchState.knownHeight)
795
+ : fetchState.knownHeight
803
796
 
804
797
  {
805
- chainId: cf.chainConfig.id->Int.toFloat,
798
+ chainId: (cs->ChainState.chainConfig).id->Int.toFloat,
806
799
  poweredByHyperSync: (
807
- cf.sourceManager->SourceManager.getActiveSource
800
+ cs->ChainState.sourceManager->SourceManager.getActiveSource
808
801
  ).poweredByHyperSync,
809
802
  latestFetchedBlockNumber,
810
803
  knownHeight,
811
804
  numBatchesFetched: 0,
812
- startBlock: cf.fetchState.startBlock,
813
- endBlock: cf.fetchState.endBlock,
814
- firstEventBlockNumber: cf.fetchState.firstEventBlock,
815
- latestProcessedBlock: cf.committedProgressBlockNumber === -1
805
+ startBlock: fetchState.startBlock,
806
+ endBlock: fetchState.endBlock,
807
+ firstEventBlockNumber: fetchState.firstEventBlock,
808
+ latestProcessedBlock: cs->ChainState.committedProgressBlockNumber === -1
816
809
  ? None
817
- : Some(cf.committedProgressBlockNumber),
818
- timestampCaughtUpToHeadOrEndblock: cf.timestampCaughtUpToHeadOrEndblock,
819
- numEventsProcessed: cf.numEventsProcessed,
820
- numAddresses: cf.fetchState->FetchState.numAddresses,
810
+ : Some(cs->ChainState.committedProgressBlockNumber),
811
+ timestampCaughtUpToHeadOrEndblock: cs->ChainState.timestampCaughtUpToHeadOrEndblock,
812
+ numEventsProcessed: cs->ChainState.numEventsProcessed,
813
+ numAddresses: fetchState->FetchState.numAddresses,
821
814
  }
822
815
  })
823
816
  Active({
824
817
  envioVersion,
825
818
  chains,
826
- indexerStartTime: state.indexerStartTime,
819
+ indexerStartTime: state->IndexerState.indexerStartTime,
827
820
  isPreRegisteringDynamicContracts: false,
828
- rollbackOnReorg: ctx.config.shouldRollbackOnReorg,
821
+ rollbackOnReorg: config.shouldRollbackOnReorg,
829
822
  })
830
823
  }
831
824
  }
832
825
  )
833
826
  }
834
827
 
835
- let chainManager = ChainManager.makeFromDbState(
836
- ~initialState=ctx.persistence->Persistence.getInitializedState,
837
- ~config=ctx.config,
838
- ~registrations=ctx.registrations,
839
- )
840
- let globalState = GlobalState.make(
841
- ~ctx,
842
- ~chainManager,
828
+ let state = IndexerState.makeFromDbState(
829
+ ~config,
830
+ ~persistence,
831
+ ~initialState=persistence->Persistence.getInitializedState,
832
+ ~registrations,
843
833
  ~isDevelopmentMode,
844
834
  ~shouldUseTui,
845
835
  ~exitAfterFirstEventBlock,
846
836
  ~onError,
847
837
  )
848
- let gsManager =
849
- globalState->GlobalStateManager.make(
850
- ~reducers=GlobalState.makeReducers(
851
- ~markBatchProcessed=MarkBatchProcessedAdapter.make(~inMemoryStore=ctx.inMemoryStore),
852
- ),
853
- ~onError=exn =>
854
- onError(exn->ErrorHandling.make(~msg="Indexer has failed with an unexpected error")),
855
- )
856
838
  if shouldUseTui {
857
- let _rerender = Tui.start(~getState=() => gsManager->GlobalStateManager.getState)
839
+ let _rerender = Tui.start(~getState=() => state)
858
840
  }
859
- globalGsManagerRef := Some(gsManager)
860
- gsManager->GlobalStateManager.dispatchTask(NextQuery(CheckAllChains))
861
- /*
862
- NOTE:
863
- This `ProcessEventBatch` dispatch shouldn't be necessary but we are adding for safety, it should immediately return doing
864
- nothing since there is no events on the queues.
865
- */
866
-
867
- gsManager->GlobalStateManager.dispatchTask(ProcessEventBatch)
841
+ indexerStateRef := Some(state)
842
+ state->IndexerLoop.start
868
843
  }
package/src/Main.res.mjs CHANGED
@@ -10,17 +10,16 @@ import Express from "express";
10
10
  import * as Process from "process";
11
11
  import * as ChainMap from "./ChainMap.res.mjs";
12
12
  import * as PgStorage from "./PgStorage.res.mjs";
13
+ import * as ChainState from "./ChainState.res.mjs";
13
14
  import * as FetchState from "./FetchState.res.mjs";
14
15
  import * as Prometheus from "./Prometheus.res.mjs";
15
- import * as GlobalState from "./GlobalState.res.mjs";
16
+ import * as IndexerLoop from "./IndexerLoop.res.mjs";
16
17
  import * as Persistence from "./Persistence.res.mjs";
17
18
  import * as PromClient from "prom-client";
18
19
  import Yargs from "yargs/yargs";
19
- import * as ChainFetcher from "./ChainFetcher.res.mjs";
20
- import * as ChainManager from "./ChainManager.res.mjs";
20
+ import * as IndexerState from "./IndexerState.res.mjs";
21
21
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
22
22
  import * as HandlerLoader from "./HandlerLoader.res.mjs";
23
- import * as InMemoryStore from "./InMemoryStore.res.mjs";
24
23
  import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
25
24
  import * as SourceManager from "./sources/SourceManager.res.mjs";
26
25
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
@@ -30,9 +29,7 @@ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
30
29
  import * as HandlerRegister from "./HandlerRegister.res.mjs";
31
30
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
32
31
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
33
- import * as GlobalStateManager from "./GlobalStateManager.res.mjs";
34
32
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
35
- import * as MarkBatchProcessedAdapter from "./adapters/MarkBatchProcessedAdapter.res.mjs";
36
33
 
37
34
  let chainDataSchema = S$RescriptSchema.schema(s => ({
38
35
  chainId: s.m(S$RescriptSchema.float),
@@ -78,7 +75,7 @@ let defaultBlockRange = {
78
75
  _every: 1
79
76
  };
80
77
 
81
- let globalGsManagerRef = {
78
+ let indexerStateRef = {
82
79
  contents: undefined
83
80
  };
84
81
 
@@ -139,9 +136,9 @@ function buildChainsObject(config) {
139
136
  }), "isRealtime", {
140
137
  enumerable: true,
141
138
  get: () => {
142
- let gsManager = globalGsManagerRef.contents;
143
- if (gsManager !== undefined) {
144
- return GlobalStateManager.getState(Primitive_option.valFromOption(gsManager)).chainManager.isRealtime;
139
+ let state = indexerStateRef.contents;
140
+ if (state !== undefined) {
141
+ return IndexerState.isRealtime(Primitive_option.valFromOption(state));
145
142
  } else if (Env.updateSyncTimeOnRestart) {
146
143
  return false;
147
144
  } else {
@@ -167,12 +164,11 @@ function buildChainsObject(config) {
167
164
  }), "addresses", {
168
165
  enumerable: true,
169
166
  get: () => {
170
- let gsManager = globalGsManagerRef.contents;
171
- if (gsManager !== undefined) {
172
- let state = GlobalStateManager.getState(Primitive_option.valFromOption(gsManager));
167
+ let state = indexerStateRef.contents;
168
+ if (state !== undefined) {
173
169
  let chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
174
- let chainFetcher = ChainMap.get(state.chainManager.chainFetchers, chain);
175
- let indexingAddresses = chainFetcher.fetchState.indexingAddresses;
170
+ let chainState = IndexerState.getChainState(Primitive_option.valFromOption(state), chain);
171
+ let indexingAddresses = ChainState.fetchState(chainState).indexingAddresses;
176
172
  let addresses = [];
177
173
  let values = Object.values(indexingAddresses);
178
174
  for (let idx = 0, idx_finish = values.length; idx < idx_finish; ++idx) {
@@ -183,12 +179,12 @@ function buildChainsObject(config) {
183
179
  }
184
180
  return addresses;
185
181
  }
186
- let chainState = getInitialChainState(chainConfig.id);
187
- if (chainState === undefined) {
182
+ let chainState$1 = getInitialChainState(chainConfig.id);
183
+ if (chainState$1 === undefined) {
188
184
  return contract.addresses;
189
185
  }
190
186
  let addresses$1 = contract.addresses.slice();
191
- chainState.indexingAddresses.forEach(dc => {
187
+ chainState$1.indexingAddresses.forEach(dc => {
192
188
  if (dc.contractName === contract.name) {
193
189
  addresses$1.push(dc.address);
194
190
  return;
@@ -450,7 +446,7 @@ function getGlobalIndexer() {
450
446
  return new Proxy(Object.create(null), traps);
451
447
  }
452
448
 
453
- function startServer(getState, ctx, isDevelopmentMode) {
449
+ function startServer(getState, persistence, isDevelopmentMode) {
454
450
  let app = Express();
455
451
  let consoleCorsMiddleware = (req, res, next) => {
456
452
  let origin = req.headers["origin"];
@@ -480,7 +476,7 @@ function startServer(getState, ctx, isDevelopmentMode) {
480
476
  });
481
477
  app.post("/console/syncCache", (_req, res) => {
482
478
  if (isDevelopmentMode) {
483
- Persistence.getInitializedStorageOrThrow(ctx.persistence).dumpEffectCache().then(() => {
479
+ Persistence.getInitializedStorageOrThrow(persistence).dumpEffectCache().then(() => {
484
480
  res.json(true);
485
481
  });
486
482
  } else {
@@ -571,14 +567,11 @@ async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockO
571
567
  let config$2 = patchConfig !== undefined ? patchConfig(config$1, registrations) : config$1;
572
568
  let onError = errHandler => {
573
569
  ErrorHandling.log(errHandler);
574
- Process.exit(1);
575
- };
576
- let ctx_inMemoryStore = InMemoryStore.make(persistence$1.allEntities, Persistence.getInitializedState(persistence$1).checkpointId, persistence$1, config$2, exn => onError(ErrorHandling.make(exn, undefined, "Failed writing batch to the database")));
577
- let ctx = {
578
- registrations: registrations,
579
- config: config$2,
580
- persistence: persistence$1,
581
- inMemoryStore: ctx_inMemoryStore
570
+ if (isTest) {
571
+ setImmediate(() => ErrorHandling.raiseExn(errHandler));
572
+ } else {
573
+ Process.exit(1);
574
+ }
582
575
  };
583
576
  let envioVersion = Utils.EnvioPackage.value.version;
584
577
  Prometheus.Info.set(envioVersion);
@@ -586,53 +579,48 @@ async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockO
586
579
  Prometheus.RollbackEnabled.set(config$2.shouldRollbackOnReorg);
587
580
  if (!isTest) {
588
581
  startServer(() => {
589
- let gsManager = globalGsManagerRef.contents;
590
- if (gsManager === undefined) {
582
+ let state = indexerStateRef.contents;
583
+ if (state === undefined) {
591
584
  return {
592
585
  status: "initializing"
593
586
  };
594
587
  }
595
- let state = GlobalStateManager.getState(Primitive_option.valFromOption(gsManager));
596
- let chains = ChainMap.values(state.chainManager.chainFetchers).map(cf => {
597
- let latestFetchedBlockNumber = Primitive_int.max(FetchState.bufferBlockNumber(cf.fetchState), 0);
598
- let knownHeight = ChainFetcher.hasProcessedToEndblock(cf) ? Stdlib_Option.getOr(cf.fetchState.endBlock, cf.fetchState.knownHeight) : cf.fetchState.knownHeight;
588
+ let state$1 = Primitive_option.valFromOption(state);
589
+ let chains = Object.values(IndexerState.chainStates(state$1)).map(cs => {
590
+ let fetchState = ChainState.fetchState(cs);
591
+ let latestFetchedBlockNumber = Primitive_int.max(FetchState.bufferBlockNumber(fetchState), 0);
592
+ let knownHeight = ChainState.hasProcessedToEndblock(cs) ? Stdlib_Option.getOr(fetchState.endBlock, fetchState.knownHeight) : fetchState.knownHeight;
599
593
  return {
600
- chainId: cf.chainConfig.id,
601
- poweredByHyperSync: SourceManager.getActiveSource(cf.sourceManager).poweredByHyperSync,
602
- firstEventBlockNumber: cf.fetchState.firstEventBlock,
603
- latestProcessedBlock: cf.committedProgressBlockNumber === -1 ? undefined : cf.committedProgressBlockNumber,
604
- timestampCaughtUpToHeadOrEndblock: cf.timestampCaughtUpToHeadOrEndblock,
605
- numEventsProcessed: cf.numEventsProcessed,
594
+ chainId: ChainState.chainConfig(cs).id,
595
+ poweredByHyperSync: SourceManager.getActiveSource(ChainState.sourceManager(cs)).poweredByHyperSync,
596
+ firstEventBlockNumber: fetchState.firstEventBlock,
597
+ latestProcessedBlock: ChainState.committedProgressBlockNumber(cs) === -1 ? undefined : ChainState.committedProgressBlockNumber(cs),
598
+ timestampCaughtUpToHeadOrEndblock: ChainState.timestampCaughtUpToHeadOrEndblock(cs),
599
+ numEventsProcessed: ChainState.numEventsProcessed(cs),
606
600
  latestFetchedBlockNumber: latestFetchedBlockNumber,
607
601
  currentBlockHeight: knownHeight,
608
602
  numBatchesFetched: 0,
609
- startBlock: cf.fetchState.startBlock,
610
- endBlock: cf.fetchState.endBlock,
611
- numAddresses: FetchState.numAddresses(cf.fetchState)
603
+ startBlock: fetchState.startBlock,
604
+ endBlock: fetchState.endBlock,
605
+ numAddresses: FetchState.numAddresses(fetchState)
612
606
  };
613
607
  });
614
608
  return {
615
609
  status: "active",
616
610
  envioVersion: envioVersion,
617
611
  chains: chains,
618
- indexerStartTime: state.indexerStartTime,
612
+ indexerStartTime: IndexerState.indexerStartTime(state$1),
619
613
  isPreRegisteringDynamicContracts: false,
620
614
  rollbackOnReorg: config$2.shouldRollbackOnReorg
621
615
  };
622
- }, ctx, isDevelopmentMode);
616
+ }, persistence$1, isDevelopmentMode);
623
617
  }
624
- let chainManager = ChainManager.makeFromDbState(Persistence.getInitializedState(persistence$1), config$2, registrations, undefined);
625
- let globalState = GlobalState.make(ctx, chainManager, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError);
626
- let gsManager = GlobalStateManager.make(globalState, GlobalState.makeReducers(undefined, undefined, undefined, MarkBatchProcessedAdapter.make(ctx_inMemoryStore)), exn => onError(ErrorHandling.make(exn, undefined, "Indexer has failed with an unexpected error")));
618
+ let state = IndexerState.makeFromDbState(config$2, persistence$1, Persistence.getInitializedState(persistence$1), registrations, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, undefined, undefined, onError);
627
619
  if (shouldUseTui) {
628
- Tui.start(() => GlobalStateManager.getState(gsManager));
620
+ Tui.start(() => state);
629
621
  }
630
- globalGsManagerRef.contents = Primitive_option.some(gsManager);
631
- GlobalStateManager.dispatchTask(gsManager, {
632
- TAG: "NextQuery",
633
- _0: "CheckAllChains"
634
- });
635
- return GlobalStateManager.dispatchTask(gsManager, "ProcessEventBatch");
622
+ indexerStateRef.contents = Primitive_option.some(state);
623
+ return IndexerLoop.start(state);
636
624
  }
637
625
 
638
626
  export {
@@ -640,7 +628,7 @@ export {
640
628
  stateSchema,
641
629
  blockRangeSchema,
642
630
  defaultBlockRange,
643
- globalGsManagerRef,
631
+ indexerStateRef,
644
632
  globalPersistenceRef,
645
633
  getInitialChainState,
646
634
  buildChainsObject,
package/src/PgStorage.res CHANGED
@@ -308,7 +308,12 @@ let rec makeFilterCondition = (
308
308
  }),
309
309
  )
310
310
  }
311
- let serializeParamOrThrow = (~queryField: Table.queryField, ~fieldName, ~fieldValue: unknown, ~isArray) => {
311
+ let serializeParamOrThrow = (
312
+ ~queryField: Table.queryField,
313
+ ~fieldName,
314
+ ~fieldValue: unknown,
315
+ ~isArray,
316
+ ) => {
312
317
  let param = try fieldValue->S.reverseConvertToJsonOrThrow(
313
318
  isArray ? queryField.arrayFieldSchema : queryField.fieldSchema,
314
319
  ) catch {
@@ -815,74 +820,6 @@ let executeSet = (
815
820
  }
816
821
  }
817
822
 
818
- let convertFieldsToJson = (fields: option<dict<unknown>>) => {
819
- switch fields {
820
- | None => %raw(`{}`)
821
- | Some(fields) =>
822
- // Convert bigint fields to string. There are no fields with nested
823
- // bigints, so iterating only the top level is safe.
824
- fields
825
- ->Utils.Dict.mapValues(value =>
826
- typeof(value) === #bigint
827
- ? value
828
- ->(Utils.magic: unknown => bigint)
829
- ->BigInt.toString
830
- ->(Utils.magic: string => unknown)
831
- : value
832
- )
833
- ->(Utils.magic: dict<unknown> => JSON.t)
834
- }
835
- }
836
-
837
- let makeRawEvent = (
838
- eventItem: Internal.eventItem,
839
- ~config: Config.t,
840
- ): InternalTable.RawEvents.t => {
841
- let {event, eventConfig, chain, blockNumber, blockHash, timestamp: blockTimestamp} = eventItem
842
- let {block, transaction, params, logIndex, srcAddress} = event->Internal.toGenericEvent
843
- let chainId = chain->ChainMap.Chain.toChainId
844
- let eventId = EventUtils.packEventIndex(~logIndex, ~blockNumber)
845
- let blockFields =
846
- block
847
- ->(Utils.magic: Internal.eventBlock => option<dict<unknown>>)
848
- ->convertFieldsToJson
849
- let transactionFields =
850
- transaction
851
- ->(Utils.magic: Internal.eventTransaction => option<dict<unknown>>)
852
- ->convertFieldsToJson
853
-
854
- blockFields->config.ecosystem.cleanUpRawEventFieldsInPlace
855
-
856
- // Serialize to unknown, because serializing to Js.Json.t fails for Bytes Fuel type, since it has unknown schema
857
- let params =
858
- params
859
- ->S.reverseConvertOrThrow(eventConfig.paramsRawEventSchema)
860
- ->(Utils.magic: unknown => JSON.t)
861
- let params = if params === %raw(`null`) {
862
- // Should probably make the params field nullable
863
- // But this is currently needed to make events
864
- // with empty params work
865
- %raw(`"null"`)
866
- } else {
867
- params
868
- }
869
-
870
- {
871
- chainId,
872
- eventId,
873
- eventName: eventConfig.name,
874
- contractName: eventConfig.contractName,
875
- blockNumber,
876
- logIndex,
877
- srcAddress,
878
- blockHash,
879
- blockTimestamp,
880
- blockFields,
881
- transactionFields,
882
- params,
883
- }
884
- }
885
-
886
823
  let rec writeBatch = async (
887
824
  sql,
888
825
  ~batch: Batch.t,
@@ -906,7 +843,7 @@ let rec writeBatch = async (
906
843
  let rawEvents = if config.enableRawEvents {
907
844
  let rows = batch.items->Array.filterMap(item =>
908
845
  switch item {
909
- | Internal.Event(_) => Some(item->Internal.castUnsafeEventItem->makeRawEvent(~config))
846
+ | Internal.Event(_) => Some(config.ecosystem.toRawEvent(item->Internal.castUnsafeEventItem))
910
847
  | Internal.Block(_) => None
911
848
  }
912
849
  )
@@ -1493,7 +1430,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1493
1430
  numEventsProcessed: 0.,
1494
1431
  firstEventBlockNumber: None,
1495
1432
  timestampCaughtUpToHeadOrEndblock: None,
1496
- indexingAddresses: ChainFetcher.configAddresses(chainConfig),
1433
+ indexingAddresses: ChainState.configAddresses(chainConfig),
1497
1434
  sourceBlockNumber: 0,
1498
1435
  }),
1499
1436
  checkpointId: InternalTable.Checkpoints.initialCheckpointId,
@@ -13,10 +13,9 @@ import * as Schema from "./db/Schema.res.mjs";
13
13
  import * as Logging from "./Logging.res.mjs";
14
14
  import * as Internal from "./Internal.res.mjs";
15
15
  import Postgres from "postgres";
16
- import * as EventUtils from "./EventUtils.res.mjs";
16
+ import * as ChainState from "./ChainState.res.mjs";
17
17
  import * as Prometheus from "./Prometheus.res.mjs";
18
18
  import * as Persistence from "./Persistence.res.mjs";
19
- import * as ChainFetcher from "./ChainFetcher.res.mjs";
20
19
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
21
20
  import * as EntityHistory from "./db/EntityHistory.res.mjs";
22
21
  import * as InternalTable from "./db/InternalTable.res.mjs";
@@ -608,47 +607,6 @@ function executeSet(sql, items, dbFunction) {
608
607
  }
609
608
  }
610
609
 
611
- function convertFieldsToJson(fields) {
612
- if (fields !== undefined) {
613
- return Utils.Dict.mapValues(fields, value => {
614
- if (typeof value === "bigint") {
615
- return value.toString();
616
- } else {
617
- return value;
618
- }
619
- });
620
- } else {
621
- return {};
622
- }
623
- }
624
-
625
- function makeRawEvent(eventItem, config) {
626
- let event = eventItem.event;
627
- let blockNumber = eventItem.blockNumber;
628
- let eventConfig = eventItem.eventConfig;
629
- let logIndex = event.logIndex;
630
- let eventId = EventUtils.packEventIndex(blockNumber, logIndex);
631
- let blockFields = convertFieldsToJson(event.block);
632
- let transactionFields = convertFieldsToJson(event.transaction);
633
- config.ecosystem.cleanUpRawEventFieldsInPlace(blockFields);
634
- let params = S$RescriptSchema.reverseConvertOrThrow(event.params, eventConfig.paramsRawEventSchema);
635
- let params$1 = params === null ? "null" : params;
636
- return {
637
- chain_id: eventItem.chain,
638
- event_id: eventId,
639
- event_name: eventConfig.name,
640
- contract_name: eventConfig.contractName,
641
- block_number: blockNumber,
642
- log_index: logIndex,
643
- src_address: event.srcAddress,
644
- block_hash: eventItem.blockHash,
645
- block_timestamp: eventItem.timestamp,
646
- block_fields: blockFields,
647
- transaction_fields: transactionFields,
648
- params: params$1
649
- };
650
- }
651
-
652
610
  async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, updatedEffectsCache, updatedEntities, sinkPromise, chainMetaData, escapeTables) {
653
611
  try {
654
612
  let shouldSaveHistory = Config.shouldSaveHistory(config, isInReorgThreshold);
@@ -659,7 +617,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
659
617
  if (config.enableRawEvents) {
660
618
  let rows = Stdlib_Array.filterMap(batch.items, item => {
661
619
  if (item.kind === 0) {
662
- return makeRawEvent(item, config);
620
+ return config.ecosystem.toRawEvent(item);
663
621
  }
664
622
  });
665
623
  if (escapeTables !== undefined && Primitive_option.valFromOption(escapeTables).has(InternalTable.RawEvents.table)) {
@@ -1004,7 +962,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1004
962
  numEventsProcessed: 0,
1005
963
  firstEventBlockNumber: undefined,
1006
964
  timestampCaughtUpToHeadOrEndblock: undefined,
1007
- indexingAddresses: ChainFetcher.configAddresses(chainConfig),
965
+ indexingAddresses: ChainState.configAddresses(chainConfig),
1008
966
  sourceBlockNumber: 0
1009
967
  })),
1010
968
  checkpointId: InternalTable.Checkpoints.initialCheckpointId,
@@ -1275,8 +1233,6 @@ export {
1275
1233
  deleteByIdsOrThrow,
1276
1234
  makeInsertDeleteUpdatesQuery,
1277
1235
  executeSet,
1278
- convertFieldsToJson,
1279
- makeRawEvent,
1280
1236
  writeBatch,
1281
1237
  makeGetRollbackRestoredEntitiesQuery,
1282
1238
  makeGetRollbackRemovedIdsQuery,
@@ -351,18 +351,6 @@ module IndexingAddresses = {
351
351
  }
352
352
  }
353
353
 
354
- module IndexingMaxConcurrency = {
355
- let gauge = SafeGauge.makeOrThrow(
356
- ~name="envio_indexing_max_concurrency",
357
- ~help="The maximum number of concurrent queries to the chain data-source.",
358
- ~labelSchema=chainIdLabelsSchema,
359
- )
360
-
361
- let set = (~maxConcurrency, ~chainId) => {
362
- gauge->SafeGauge.handleInt(~labels=chainId, ~value=maxConcurrency)
363
- }
364
- }
365
-
366
354
  module IndexingConcurrency = {
367
355
  let gauge = SafeGauge.makeOrThrow(
368
356
  ~name="envio_indexing_concurrency",
@@ -426,7 +414,7 @@ module IndexingBufferSize = {
426
414
  module IndexingTargetBufferSize = {
427
415
  let gauge = PromClient.Gauge.makeGauge({
428
416
  "name": "envio_indexing_target_buffer_size",
429
- "help": "The target buffer size per chain for indexing. The actual number of items in the queue may exceed this value, but the indexer always tries to keep the buffer filled up to this target.",
417
+ "help": "The indexer-wide target buffer size shared across all chains. The actual number of items in the queue may exceed this value, but the indexer always tries to keep the buffer filled up to this target.",
430
418
  })
431
419
 
432
420
  let set = (~targetBufferSize) => {