envio 3.3.0-alpha.3 → 3.3.0-alpha.5

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 (53) hide show
  1. package/evm.schema.json +10 -0
  2. package/package.json +7 -7
  3. package/src/Batch.res.mjs +1 -1
  4. package/src/Bin.res +3 -0
  5. package/src/Bin.res.mjs +4 -0
  6. package/src/ChainFetching.res +1 -3
  7. package/src/ChainFetching.res.mjs +3 -3
  8. package/src/ChainState.res +44 -19
  9. package/src/ChainState.res.mjs +25 -23
  10. package/src/ChainState.resi +3 -3
  11. package/src/Config.res +3 -0
  12. package/src/Config.res.mjs +3 -1
  13. package/src/Core.res +0 -3
  14. package/src/Ecosystem.res +0 -4
  15. package/src/EventConfigBuilder.res +3 -0
  16. package/src/EventConfigBuilder.res.mjs +7 -1
  17. package/src/FetchState.res +73 -160
  18. package/src/FetchState.res.mjs +120 -222
  19. package/src/IndexingAddresses.res +105 -0
  20. package/src/IndexingAddresses.res.mjs +100 -0
  21. package/src/IndexingAddresses.resi +32 -0
  22. package/src/Internal.res +5 -0
  23. package/src/Main.res +21 -24
  24. package/src/Main.res.mjs +21 -20
  25. package/src/Metrics.res +33 -0
  26. package/src/Metrics.res.mjs +39 -0
  27. package/src/Prometheus.res +2 -20
  28. package/src/Prometheus.res.mjs +83 -95
  29. package/src/SimulateItems.res +4 -0
  30. package/src/TestIndexer.res +43 -17
  31. package/src/TestIndexer.res.mjs +16 -9
  32. package/src/bindings/Viem.res +0 -41
  33. package/src/bindings/Viem.res.mjs +1 -43
  34. package/src/sources/Evm.res +17 -39
  35. package/src/sources/Evm.res.mjs +8 -40
  36. package/src/sources/EvmChain.res +3 -1
  37. package/src/sources/EvmChain.res.mjs +2 -1
  38. package/src/sources/EvmRpcClient.res +36 -5
  39. package/src/sources/EvmRpcClient.res.mjs +7 -4
  40. package/src/sources/Fuel.res +0 -2
  41. package/src/sources/Fuel.res.mjs +0 -1
  42. package/src/sources/HyperSyncClient.res +0 -35
  43. package/src/sources/HyperSyncClient.res.mjs +1 -8
  44. package/src/sources/Rpc.res +15 -47
  45. package/src/sources/Rpc.res.mjs +25 -56
  46. package/src/sources/RpcSource.res +30 -73
  47. package/src/sources/RpcSource.res.mjs +24 -73
  48. package/src/sources/SourceManager.res +1 -1
  49. package/src/sources/SourceManager.res.mjs +1 -1
  50. package/src/sources/Svm.res +10 -17
  51. package/src/sources/Svm.res.mjs +6 -18
  52. package/src/sources/TransactionStore.res +98 -76
  53. package/src/sources/TransactionStore.res.mjs +49 -35
@@ -0,0 +1,105 @@
1
+ type indexingAddress = Internal.indexingContract
2
+
3
+ type contractConfig = {startBlock: option<int>}
4
+
5
+ type t = dict<indexingAddress>
6
+
7
+ let deriveEffectiveStartBlock = (~registrationBlock: int, ~contractStartBlock: option<int>) => {
8
+ Pervasives.max(Pervasives.max(registrationBlock, 0), contractStartBlock->Option.getOr(0))
9
+ }
10
+
11
+ let makeContractConfigs = (~eventConfigs: array<Internal.eventConfig>): dict<contractConfig> => {
12
+ let contractConfigs: dict<contractConfig> = Dict.make()
13
+ eventConfigs->Array.forEach(ec => {
14
+ switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(ec.contractName) {
15
+ | Some({startBlock}) =>
16
+ contractConfigs->Dict.set(
17
+ ec.contractName,
18
+ {
19
+ startBlock: switch (startBlock, ec.startBlock) {
20
+ | (Some(a), Some(b)) => Some(Pervasives.min(a, b))
21
+ | (Some(_) as s, None) | (None, Some(_) as s) => s
22
+ | (None, None) => None
23
+ },
24
+ },
25
+ )
26
+ | None =>
27
+ contractConfigs->Dict.set(
28
+ ec.contractName,
29
+ {
30
+ startBlock: ec.startBlock,
31
+ },
32
+ )
33
+ }
34
+ })
35
+ contractConfigs
36
+ }
37
+
38
+ let makeIndexingAddress = (
39
+ ~contract: Internal.indexingAddress,
40
+ ~contractConfigs: dict<contractConfig>,
41
+ ): indexingAddress => {
42
+ let contractStartBlock = switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(
43
+ contract.contractName,
44
+ ) {
45
+ | Some({startBlock}) => startBlock
46
+ | None => None
47
+ }
48
+ {
49
+ address: contract.address,
50
+ contractName: contract.contractName,
51
+ registrationBlock: contract.registrationBlock,
52
+ effectiveStartBlock: deriveEffectiveStartBlock(
53
+ ~registrationBlock=contract.registrationBlock,
54
+ ~contractStartBlock,
55
+ ),
56
+ }
57
+ }
58
+
59
+ let make = (
60
+ ~contractConfigs: dict<contractConfig>,
61
+ ~addresses: array<Internal.indexingAddress>,
62
+ ): t => {
63
+ let indexingAddresses = Dict.make()
64
+ addresses->Array.forEach(contract => {
65
+ indexingAddresses->Dict.set(
66
+ contract.address->Address.toString,
67
+ makeIndexingAddress(~contract, ~contractConfigs),
68
+ )
69
+ })
70
+ indexingAddresses
71
+ }
72
+
73
+ let get = (indexingAddresses: t, address) =>
74
+ indexingAddresses->Utils.Dict.dangerouslyGetNonOption(address)
75
+
76
+ let size = (indexingAddresses: t) => indexingAddresses->Utils.Dict.size
77
+
78
+ let getContractAddresses = (indexingAddresses: t, ~contractName): array<Address.t> => {
79
+ let addresses = []
80
+ indexingAddresses->Utils.Dict.forEach(ia => {
81
+ if ia.contractName === contractName {
82
+ addresses->Array.push(ia.address)
83
+ }
84
+ })
85
+ addresses
86
+ }
87
+
88
+ // Underlying dict for the precompiled `clientAddressFilter` only — it does raw
89
+ // `indexingAddresses[srcAddress]` access in generated JS and can't take the opaque
90
+ // type. Don't reach for this elsewhere; use the domain accessors above.
91
+ let rawForFilter = (indexingAddresses: t): dict<indexingAddress> => indexingAddresses
92
+
93
+ let register = (indexingAddresses: t, additions: dict<indexingAddress>) => {
94
+ let _ = Utils.Dict.mergeInPlace(indexingAddresses, additions)
95
+ }
96
+
97
+ let rollbackInPlace = (indexingAddresses: t, ~targetBlockNumber: int): unit => {
98
+ // forEachWithKey is a `for..in`, so deleting the key currently being visited is
99
+ // safe — it doesn't affect enumeration of the remaining keys.
100
+ indexingAddresses->Utils.Dict.forEachWithKey((indexingContract, address) => {
101
+ if indexingContract.registrationBlock > targetBlockNumber {
102
+ indexingAddresses->Utils.Dict.deleteInPlace(address)
103
+ }
104
+ })
105
+ }
@@ -0,0 +1,100 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Utils from "./Utils.res.mjs";
4
+ import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+
7
+ function deriveEffectiveStartBlock(registrationBlock, contractStartBlock) {
8
+ return Primitive_int.max(Primitive_int.max(registrationBlock, 0), Stdlib_Option.getOr(contractStartBlock, 0));
9
+ }
10
+
11
+ function makeContractConfigs(eventConfigs) {
12
+ let contractConfigs = {};
13
+ eventConfigs.forEach(ec => {
14
+ let match = contractConfigs[ec.contractName];
15
+ if (match !== undefined) {
16
+ let startBlock = match.startBlock;
17
+ let match$1 = ec.startBlock;
18
+ contractConfigs[ec.contractName] = {
19
+ startBlock: startBlock !== undefined ? (
20
+ match$1 !== undefined ? Primitive_int.min(startBlock, match$1) : startBlock
21
+ ) : (
22
+ match$1 !== undefined ? match$1 : undefined
23
+ )
24
+ };
25
+ return;
26
+ }
27
+ contractConfigs[ec.contractName] = {
28
+ startBlock: ec.startBlock
29
+ };
30
+ });
31
+ return contractConfigs;
32
+ }
33
+
34
+ function makeIndexingAddress(contract, contractConfigs) {
35
+ let match = contractConfigs[contract.contractName];
36
+ let contractStartBlock = match !== undefined ? match.startBlock : undefined;
37
+ return {
38
+ address: contract.address,
39
+ contractName: contract.contractName,
40
+ registrationBlock: contract.registrationBlock,
41
+ effectiveStartBlock: deriveEffectiveStartBlock(contract.registrationBlock, contractStartBlock)
42
+ };
43
+ }
44
+
45
+ function make(contractConfigs, addresses) {
46
+ let indexingAddresses = {};
47
+ addresses.forEach(contract => {
48
+ indexingAddresses[contract.address] = makeIndexingAddress(contract, contractConfigs);
49
+ });
50
+ return indexingAddresses;
51
+ }
52
+
53
+ function get(indexingAddresses, address) {
54
+ return indexingAddresses[address];
55
+ }
56
+
57
+ function size(indexingAddresses) {
58
+ return Utils.Dict.size(indexingAddresses);
59
+ }
60
+
61
+ function getContractAddresses(indexingAddresses, contractName) {
62
+ let addresses = [];
63
+ Utils.Dict.forEach(indexingAddresses, ia => {
64
+ if (ia.contractName === contractName) {
65
+ addresses.push(ia.address);
66
+ return;
67
+ }
68
+ });
69
+ return addresses;
70
+ }
71
+
72
+ function rawForFilter(indexingAddresses) {
73
+ return indexingAddresses;
74
+ }
75
+
76
+ function register(indexingAddresses, additions) {
77
+ Object.assign(indexingAddresses, additions);
78
+ }
79
+
80
+ function rollbackInPlace(indexingAddresses, targetBlockNumber) {
81
+ Utils.Dict.forEachWithKey(indexingAddresses, (indexingContract, address) => {
82
+ if (indexingContract.registrationBlock > targetBlockNumber) {
83
+ return Utils.Dict.deleteInPlace(indexingAddresses, address);
84
+ }
85
+ });
86
+ }
87
+
88
+ export {
89
+ deriveEffectiveStartBlock,
90
+ makeContractConfigs,
91
+ makeIndexingAddress,
92
+ make,
93
+ get,
94
+ size,
95
+ getContractAddresses,
96
+ rawForFilter,
97
+ register,
98
+ rollbackInPlace,
99
+ }
100
+ /* Utils Not a pure module */
@@ -0,0 +1,32 @@
1
+ type indexingAddress = Internal.indexingContract
2
+
3
+ type contractConfig = {startBlock: option<int>}
4
+
5
+ type t
6
+
7
+ let deriveEffectiveStartBlock: (~registrationBlock: int, ~contractStartBlock: option<int>) => int
8
+
9
+ let makeContractConfigs: (~eventConfigs: array<Internal.eventConfig>) => dict<contractConfig>
10
+
11
+ let makeIndexingAddress: (
12
+ ~contract: Internal.indexingAddress,
13
+ ~contractConfigs: dict<contractConfig>,
14
+ ) => indexingAddress
15
+
16
+ let make: (~contractConfigs: dict<contractConfig>, ~addresses: array<Internal.indexingAddress>) => t
17
+
18
+ let get: (t, string) => option<indexingAddress>
19
+
20
+ let size: t => int
21
+
22
+ let getContractAddresses: (t, ~contractName: string) => array<Address.t>
23
+
24
+ // Underlying dict for the precompiled `clientAddressFilter` only, which does raw
25
+ // `indexingAddresses[srcAddress]` access in generated JS. Don't use elsewhere —
26
+ // prefer the domain accessors so the opaque type stays enforced.
27
+ let rawForFilter: t => dict<indexingAddress>
28
+
29
+ let register: (t, dict<indexingAddress>) => unit
30
+
31
+ // Deletes addresses registered after `targetBlockNumber` from the index in place.
32
+ let rollbackInPlace: (t, ~targetBlockNumber: int) => unit
package/src/Internal.res CHANGED
@@ -420,6 +420,11 @@ type eventConfig = private {
420
420
  // string set so the shared mask logic is ecosystem-agnostic; sources recover
421
421
  // the typed view where they need it.
422
422
  selectedTransactionFields: Utils.Set.t<string>,
423
+ // `selectedTransactionFields` precompiled to the transaction-store selection
424
+ // bitmask (bit per ecosystem field code). Materialisation reads this per item
425
+ // so each transaction decodes only the fields its event selected. `0.` when
426
+ // nothing is selected or the ecosystem carries the transaction inline (Fuel).
427
+ transactionFieldMask: float,
423
428
  }
424
429
 
425
430
  type fuelEventKind =
package/src/Main.res CHANGED
@@ -168,18 +168,7 @@ let buildChainsObject = (~config: Config.t) => {
168
168
  | Some(state) => {
169
169
  let chain = ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)
170
170
  let chainState = state->IndexerState.getChainState(~chain)
171
- let indexingAddresses = chainState->ChainState.indexingAddresses
172
-
173
- // Collect all addresses for this contract name from indexingAddresses
174
- let addresses = []
175
- let values = indexingAddresses->Dict.valuesToArray
176
- for idx in 0 to values->Array.length - 1 {
177
- let indexingContract = values->Array.getUnsafe(idx)
178
- if indexingContract.contractName === contract.name {
179
- addresses->Array.push(indexingContract.address)->ignore
180
- }
181
- }
182
- addresses
171
+ chainState->ChainState.contractAddresses(~contractName=contract.name)
183
172
  }
184
173
  // Before the global state is available (eg during handler
185
174
  // module load after resume), combine static addresses from config
@@ -627,9 +616,9 @@ let startServer = (~getState, ~persistence: Persistence.t, ~isDevelopmentMode: b
627
616
  app->get("/metrics", (_req, res) => {
628
617
  res->set("Content-Type", PromClient.defaultRegister->PromClient.getContentType)
629
618
  let _ =
630
- PromClient.defaultRegister
631
- ->PromClient.metrics
632
- ->Promise.thenResolve(metrics => res->endWithData(metrics))
619
+ Metrics.collect(~state=indexerStateRef.contents)->Promise.thenResolve(metrics =>
620
+ res->endWithData(metrics)
621
+ )
633
622
  })
634
623
 
635
624
  app->get("/metrics/runtime", (_req, res) => {
@@ -687,6 +676,10 @@ let dropSchema = async () => {
687
676
  await persistence.storage.close()
688
677
  }
689
678
 
679
+ // Rejection carried by `onError`: the failure is already logged with full
680
+ // context, so callers should act on it (exit / re-throw) without logging again.
681
+ exception FatalError(exn)
682
+
690
683
  let start = async (
691
684
  ~persistence: option<Persistence.t>=?,
692
685
  ~reset=false,
@@ -742,17 +735,20 @@ let start = async (
742
735
  | None => config
743
736
  }
744
737
  // The single fatal-error handler, invoked once via IndexerState.errorExit.
738
+ // It logs the failure once (with chain context) and rejects the run wrapped in
739
+ // `FatalError` so callers know it's already logged — `Bin.res` just exits, the
740
+ // test worker unwraps and re-throws it to the parent thread. `runUntilFatalError`
741
+ // only ever rejects: on a clean run it stays pending and the process exits via
742
+ // ExitOnCaughtUp / when the indexer loop drains.
743
+ let onErrorReject = ref(None)
744
+ let runUntilFatalError: promise<unit> = Promise.make((_resolve, reject) =>
745
+ onErrorReject := Some(reject)
746
+ )
747
+ // `onErrorReject` is filled synchronously by `Promise.make` above, before the
748
+ // indexer can run and call `onError`, so it's always present here.
745
749
  let onError = (errHandler: ErrorHandling.t) => {
746
750
  errHandler->ErrorHandling.log
747
- if isTest {
748
- // The TestIndexer runs the indexer in a worker thread and reads the
749
- // failure off the worker 'error' event. Re-throw the original error
750
- // outside the promise chain on the next tick so the test sees its real
751
- // message instead of a generic non-zero exit code.
752
- NodeJs.setImmediate(() => errHandler->ErrorHandling.raiseExn)
753
- } else {
754
- NodeJs.process->NodeJs.exitWithCode(Failure)
755
- }
751
+ (onErrorReject.contents->Option.getUnsafe)(FatalError(errHandler.exn->Utils.prettifyExn))
756
752
  }
757
753
  let envioVersion = Utils.EnvioPackage.value.version
758
754
  Prometheus.Info.set(~version=envioVersion)
@@ -793,4 +789,5 @@ let start = async (
793
789
  }
794
790
  indexerStateRef := Some(state)
795
791
  state->IndexerLoop.start
792
+ await runUntilFatalError
796
793
  }
package/src/Main.res.mjs CHANGED
@@ -6,6 +6,7 @@ import * as Envio from "./Envio.res.mjs";
6
6
  import * as Utils from "./Utils.res.mjs";
7
7
  import * as Config from "./Config.res.mjs";
8
8
  import * as Logging from "./Logging.res.mjs";
9
+ import * as Metrics from "./Metrics.res.mjs";
9
10
  import Express from "express";
10
11
  import * as Process from "process";
11
12
  import * as ChainMap from "./ChainMap.res.mjs";
@@ -165,29 +166,20 @@ function buildChainsObject(config) {
165
166
  if (state !== undefined) {
166
167
  let chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
167
168
  let chainState = IndexerState.getChainState(Primitive_option.valFromOption(state), chain);
168
- let indexingAddresses = ChainState.indexingAddresses(chainState);
169
- let addresses = [];
170
- let values = Object.values(indexingAddresses);
171
- for (let idx = 0, idx_finish = values.length; idx < idx_finish; ++idx) {
172
- let indexingContract = values[idx];
173
- if (indexingContract.contractName === contract.name) {
174
- addresses.push(indexingContract.address);
175
- }
176
- }
177
- return addresses;
169
+ return ChainState.contractAddresses(chainState, contract.name);
178
170
  }
179
171
  let chainState$1 = getInitialChainState(chainConfig.id);
180
172
  if (chainState$1 === undefined) {
181
173
  return contract.addresses;
182
174
  }
183
- let addresses$1 = contract.addresses.slice();
175
+ let addresses = contract.addresses.slice();
184
176
  chainState$1.indexingAddresses.forEach(dc => {
185
177
  if (dc.contractName === contract.name) {
186
- addresses$1.push(dc.address);
178
+ addresses.push(dc.address);
187
179
  return;
188
180
  }
189
181
  });
190
- return addresses$1;
182
+ return addresses;
191
183
  }
192
184
  });
193
185
  Object.defineProperty(chainObj, contract.name, {
@@ -486,7 +478,7 @@ function startServer(getState, persistence, isDevelopmentMode) {
486
478
  });
487
479
  app.get("/metrics", (_req, res) => {
488
480
  res.set("Content-Type", PromClient.register.contentType);
489
- PromClient.register.metrics().then(metrics => res.end(metrics));
481
+ Metrics.collect(indexerStateRef.contents).then(metrics => res.end(metrics));
490
482
  });
491
483
  app.get("/metrics/runtime", (_req, res) => {
492
484
  res.set("Content-Type", runtimeRegistry.contentType);
@@ -522,6 +514,8 @@ async function dropSchema() {
522
514
  return await persistence.storage.close();
523
515
  }
524
516
 
517
+ let FatalError = /* @__PURE__ */Primitive_exceptions.create("Main.FatalError");
518
+
525
519
  async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockOpt, patchConfig) {
526
520
  let reset = resetOpt !== undefined ? resetOpt : false;
527
521
  let isTest = isTestOpt !== undefined ? isTestOpt : false;
@@ -562,13 +556,18 @@ async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockO
562
556
  allEnums: config.allEnums
563
557
  }) : config;
564
558
  let config$2 = patchConfig !== undefined ? patchConfig(config$1, registrations) : config$1;
559
+ let onErrorReject = {
560
+ contents: undefined
561
+ };
562
+ let runUntilFatalError = new Promise((_resolve, reject) => {
563
+ onErrorReject.contents = reject;
564
+ });
565
565
  let onError = errHandler => {
566
566
  ErrorHandling.log(errHandler);
567
- if (isTest) {
568
- setImmediate(() => ErrorHandling.raiseExn(errHandler));
569
- } else {
570
- Process.exit(1);
571
- }
567
+ onErrorReject.contents({
568
+ RE_EXN_ID: FatalError,
569
+ _1: Utils.prettifyExn(errHandler.exn)
570
+ });
572
571
  };
573
572
  let envioVersion = Utils.EnvioPackage.value.version;
574
573
  Prometheus.Info.set(envioVersion);
@@ -599,7 +598,8 @@ async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockO
599
598
  Tui.start(() => state);
600
599
  }
601
600
  indexerStateRef.contents = Primitive_option.some(state);
602
- return IndexerLoop.start(state);
601
+ IndexerLoop.start(state);
602
+ return await runUntilFatalError;
603
603
  }
604
604
 
605
605
  export {
@@ -616,6 +616,7 @@ export {
616
616
  getEnvioInfo,
617
617
  migrate,
618
618
  dropSchema,
619
+ FatalError,
619
620
  start,
620
621
  }
621
622
  /* chainDataSchema Not a pure module */
@@ -0,0 +1,33 @@
1
+ // Pull-based metrics computed from live indexer state at scrape time, merged with
2
+ // the imperatively-updated prom-client default registry. Used because the address
3
+ // index is mutated in place (no single update site to fire a gauge from).
4
+
5
+ let indexingAddressesName = "envio_indexing_addresses"
6
+ let indexingAddressesHelp = "The number of addresses indexed on chain. Includes both static and dynamic addresses."
7
+
8
+ // Render a gauge straight from the per-chain dict, one sample per key, without
9
+ // materialising an intermediate samples array. Accumulate into one string rather
10
+ // than building a lines array to join: `++` compiles to JS `+=`, which V8 grows
11
+ // as a ConsString instead of recopying.
12
+ let renderGauge = (~name, ~help, ~chains: dict<'a>, ~value: 'a => int) => {
13
+ let out = ref(`# HELP ${name} ${help}\n# TYPE ${name} gauge`)
14
+ let prefix = `\n${name}{chainId="`
15
+ chains->Utils.Dict.forEachWithKey((chain, chainId) => {
16
+ out := out.contents ++ prefix ++ chainId ++ `"} ` ++ value(chain)->Int.toString
17
+ })
18
+ out.contents
19
+ }
20
+
21
+ let collect = async (~state: option<IndexerState.t>) => {
22
+ let base = await PromClient.defaultRegister->PromClient.metrics
23
+ switch state {
24
+ | None => base
25
+ | Some(state) =>
26
+ `${base}${renderGauge(
27
+ ~name=indexingAddressesName,
28
+ ~help=indexingAddressesHelp,
29
+ ~chains=state->IndexerState.chainStates,
30
+ ~value=cs => (cs->ChainState.toChainData).numAddresses,
31
+ )}\n`
32
+ }
33
+ }
@@ -0,0 +1,39 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Utils from "./Utils.res.mjs";
4
+ import * as ChainState from "./ChainState.res.mjs";
5
+ import * as PromClient from "prom-client";
6
+ import * as IndexerState from "./IndexerState.res.mjs";
7
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
8
+
9
+ let indexingAddressesName = "envio_indexing_addresses";
10
+
11
+ let indexingAddressesHelp = "The number of addresses indexed on chain. Includes both static and dynamic addresses.";
12
+
13
+ function renderGauge(name, help, chains, value) {
14
+ let out = {
15
+ contents: `# HELP ` + name + ` ` + help + `\n# TYPE ` + name + ` gauge`
16
+ };
17
+ let prefix = `\n` + name + `{chainId="`;
18
+ Utils.Dict.forEachWithKey(chains, (chain, chainId) => {
19
+ out.contents = out.contents + prefix + chainId + `"} ` + value(chain).toString();
20
+ });
21
+ return out.contents;
22
+ }
23
+
24
+ async function collect(state) {
25
+ let base = await PromClient.register.metrics();
26
+ if (state !== undefined) {
27
+ return base + renderGauge(indexingAddressesName, indexingAddressesHelp, IndexerState.chainStates(Primitive_option.valFromOption(state)), cs => ChainState.toChainData(cs).numAddresses) + `\n`;
28
+ } else {
29
+ return base;
30
+ }
31
+ }
32
+
33
+ export {
34
+ indexingAddressesName,
35
+ indexingAddressesHelp,
36
+ renderGauge,
37
+ collect,
38
+ }
39
+ /* Utils Not a pure module */
@@ -246,10 +246,7 @@ module PreloadHandler = {
246
246
  )
247
247
  operations->Utils.Dict.deleteInPlace(key)
248
248
  }
249
- sumTimeCounter->SafeCounter.handleFloat(
250
- ~labels,
251
- ~value=timerRef->Performance.secondsSince,
252
- )
249
+ sumTimeCounter->SafeCounter.handleFloat(~labels, ~value=timerRef->Performance.secondsSince)
253
250
  count->SafeCounter.increment(~labels)
254
251
  }
255
252
  }
@@ -339,18 +336,6 @@ module ProcessStartTimeSeconds = {
339
336
  }
340
337
  }
341
338
 
342
- module IndexingAddresses = {
343
- let gauge = SafeGauge.makeOrThrow(
344
- ~name="envio_indexing_addresses",
345
- ~help="The number of addresses indexed on chain. Includes both static and dynamic addresses.",
346
- ~labelSchema=chainIdLabelsSchema,
347
- )
348
-
349
- let set = (~addressesCount, ~chainId) => {
350
- gauge->SafeGauge.handleInt(~labels=chainId, ~value=addressesCount)
351
- }
352
- }
353
-
354
339
  module IndexingConcurrency = {
355
340
  let gauge = SafeGauge.makeOrThrow(
356
341
  ~name="envio_indexing_concurrency",
@@ -800,10 +785,7 @@ module StorageLoad = {
800
785
  )
801
786
  operations->Utils.Dict.deleteInPlace(key)
802
787
  }
803
- sumTimeCounter->SafeCounter.handleFloat(
804
- ~labels,
805
- ~value=timerRef->Performance.secondsSince,
806
- )
788
+ sumTimeCounter->SafeCounter.handleFloat(~labels, ~value=timerRef->Performance.secondsSince)
807
789
  counter->SafeCounter.increment(~labels)
808
790
  whereSizeCounter->SafeCounter.handleInt(~labels, ~value=whereSize)
809
791
  sizeCounter->SafeCounter.handleInt(~labels, ~value=size)