envio 3.8.0 → 3.9.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 (64) hide show
  1. package/README.md +2 -2
  2. package/index.d.ts +158 -104
  3. package/package.json +6 -6
  4. package/src/AddressRows.res +121 -0
  5. package/src/AddressRows.res.mjs +143 -0
  6. package/src/Batch.res +2 -0
  7. package/src/Batch.res.mjs +2 -1
  8. package/src/ChainState.res +76 -70
  9. package/src/ChainState.res.mjs +76 -65
  10. package/src/ChainState.resi +14 -9
  11. package/src/Config.res +23 -82
  12. package/src/Config.res.mjs +19 -63
  13. package/src/ContractMapping.res +66 -0
  14. package/src/ContractMapping.res.mjs +73 -0
  15. package/src/Core.res +20 -0
  16. package/src/Core.res.mjs +4 -0
  17. package/src/EventConfigBuilder.res +0 -2
  18. package/src/EventConfigBuilder.res.mjs +0 -2
  19. package/src/FetchState.res +59 -67
  20. package/src/FetchState.res.mjs +34 -44
  21. package/src/InMemoryStore.res +17 -30
  22. package/src/InMemoryStore.res.mjs +11 -23
  23. package/src/IndexerState.res +21 -1
  24. package/src/IndexerState.res.mjs +9 -3
  25. package/src/IndexerState.resi +1 -0
  26. package/src/Main.res +25 -15
  27. package/src/Main.res.mjs +19 -14
  28. package/src/MemoryStorage.res +39 -66
  29. package/src/MemoryStorage.res.mjs +28 -65
  30. package/src/Metrics.res +15 -1
  31. package/src/Metrics.res.mjs +5 -1
  32. package/src/Persistence.res +30 -16
  33. package/src/Persistence.res.mjs +8 -5
  34. package/src/PgStorage.res +183 -65
  35. package/src/PgStorage.res.mjs +92 -58
  36. package/src/Rollback.res +14 -10
  37. package/src/Rollback.res.mjs +4 -2
  38. package/src/SimulateItems.res +5 -12
  39. package/src/SimulateItems.res.mjs +6 -10
  40. package/src/TestIndexer.res +93 -111
  41. package/src/TestIndexer.res.mjs +61 -88
  42. package/src/Utils.res +7 -0
  43. package/src/Utils.res.mjs +9 -2
  44. package/src/Writing.res +2 -0
  45. package/src/Writing.res.mjs +2 -1
  46. package/src/bindings/ClickHouse.res +6 -0
  47. package/src/bindings/ClickHouse.res.mjs +4 -0
  48. package/src/bindings/NodeJs.res +9 -0
  49. package/src/bindings/NodeJs.res.mjs +8 -1
  50. package/src/bindings/Postgres.res +9 -0
  51. package/src/bindings/Postgres.res.mjs +3 -0
  52. package/src/db/EntityHistory.res +12 -18
  53. package/src/db/EntityHistory.res.mjs +3 -14
  54. package/src/db/InternalTable.res +171 -65
  55. package/src/db/InternalTable.res.mjs +176 -73
  56. package/src/db/Table.res +24 -0
  57. package/src/db/Table.res.mjs +20 -1
  58. package/src/sources/AddressSet.res +0 -22
  59. package/src/sources/AddressStore.res +48 -88
  60. package/src/sources/AddressStore.res.mjs +11 -22
  61. package/src/sources/SvmHyperSyncClient.res +17 -21
  62. package/src/sources/SvmHyperSyncSource.res +4 -9
  63. package/src/sources/SvmHyperSyncSource.res.mjs +5 -13
  64. package/svm.schema.json +10 -4
@@ -6,6 +6,8 @@ import * as Config from "./Config.res.mjs";
6
6
  import * as ChainId from "./ChainId.res.mjs";
7
7
  import * as EntityId from "./EntityId.res.mjs";
8
8
  import * as Internal from "./Internal.res.mjs";
9
+ import * as ChainState from "./ChainState.res.mjs";
10
+ import * as AddressRows from "./AddressRows.res.mjs";
9
11
  import * as Stdlib_Null from "@rescript/runtime/lib/es6/Stdlib_Null.js";
10
12
  import * as EntityFilter from "./db/EntityFilter.res.mjs";
11
13
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
@@ -26,6 +28,7 @@ function make() {
26
28
  cache: {},
27
29
  effectCache: {},
28
30
  envioInfo: undefined,
31
+ addresses: AddressRows.Table.make(),
29
32
  isInitialized: false
30
33
  };
31
34
  }
@@ -76,58 +79,17 @@ function registerEntities(state, entities) {
76
79
  });
77
80
  }
78
81
 
79
- function seedIndexingAddresses(state, chainConfigs) {
80
- let dict = getEntityDict(state, Config.EnvioAddresses.name);
81
- chainConfigs.forEach(chainConfig => {
82
- chainConfig.contracts.forEach(contract => {
83
- contract.addresses.forEach(address => {
84
- let entity_id = Config.EnvioAddresses.makeId(chainConfig.id, address);
85
- let entity_chain_id = chainConfig.id;
86
- let entity_contract_name = contract.name;
87
- let entity = {
88
- id: entity_id,
89
- chain_id: entity_chain_id,
90
- registration_block: -1,
91
- registration_log_index: -1,
92
- contract_name: entity_contract_name
93
- };
94
- dict[entity_id] = entity;
95
- });
96
- });
97
- });
98
- }
99
-
100
- function toIndexingAddress(dc) {
101
- return {
102
- address: Config.EnvioAddresses.getAddress(dc),
103
- contractName: dc.contract_name,
104
- registrationBlock: dc.registration_block
105
- };
82
+ function seedConfigAddresses(state, chainConfigs, contractMapping, ecosystem) {
83
+ AddressRows.Table.clear(state.addresses);
84
+ ChainState.seedConfigAddresses(state.addresses, chainConfigs, ecosystem, contractMapping);
106
85
  }
107
86
 
108
- function getIndexingAddressesByChain(state) {
109
- let byChain = {};
110
- let dcDict = state.entities[Config.EnvioAddresses.name];
111
- if (dcDict !== undefined) {
112
- Object.values(dcDict).forEach(entity => {
113
- let chainIdStr = ChainId.toString(entity.chain_id);
114
- let arr = byChain[chainIdStr];
115
- let contracts;
116
- if (arr !== undefined) {
117
- contracts = arr;
118
- } else {
119
- let arr$1 = [];
120
- byChain[chainIdStr] = arr$1;
121
- contracts = arr$1;
122
- }
123
- contracts.push(toIndexingAddress(entity));
124
- });
125
- }
126
- return byChain;
87
+ function addressRowsByChain(state) {
88
+ return AddressRows.Table.groupByChain(state.addresses);
127
89
  }
128
90
 
129
91
  function toInitialChainStates(state) {
130
- let addressesByChain = getIndexingAddressesByChain(state);
92
+ let addressesByChain = AddressRows.Table.groupByChain(state.addresses);
131
93
  return Object.values(state.chains).map(chain => ({
132
94
  id: chain.id,
133
95
  startBlock: chain.startBlock,
@@ -137,7 +99,7 @@ function toInitialChainStates(state) {
137
99
  numEventsProcessed: chain.numEventsProcessed,
138
100
  firstEventBlockNumber: chain.firstEventBlockNumber,
139
101
  timestampCaughtUpToHeadOrEndblock: chain.timestampCaughtUpToHeadOrEndblock,
140
- indexingAddresses: Stdlib_Option.getOr(addressesByChain[ChainId.toString(chain.id)], []),
102
+ addressRows: Stdlib_Option.getOr(addressesByChain[ChainId.toString(chain.id)], AddressRows.emptySeedRows()),
141
103
  sourceBlockNumber: chain.sourceBlockNumber
142
104
  }));
143
105
  }
@@ -174,14 +136,15 @@ function reorgCheckpoints(state) {
174
136
  });
175
137
  }
176
138
 
177
- function toInitialState(state, cleanRun) {
139
+ function toInitialState(state, cleanRun, contractMapping) {
178
140
  return {
179
141
  cleanRun: cleanRun,
142
+ contractMapping: contractMapping,
143
+ envioInfo: state.envioInfo,
180
144
  cache: state.cache,
181
145
  chains: toInitialChainStates(state),
182
146
  checkpointId: committedCheckpointId(state),
183
- reorgCheckpoints: reorgCheckpoints(state),
184
- envioInfo: state.envioInfo
147
+ reorgCheckpoints: reorgCheckpoints(state)
185
148
  };
186
149
  }
187
150
 
@@ -227,18 +190,20 @@ function backfillHistory(state, entityConfig, scope, entityId, rows) {
227
190
  }
228
191
  }
229
192
 
230
- function applyRollback(state, targetCheckpointId) {
193
+ function applyRollback(state, targetCheckpointId, rolledBackAddresses) {
231
194
  state.checkpoints = state.checkpoints.filter(cp => cp.id <= targetCheckpointId);
195
+ rolledBackAddresses.forEach(key => AddressRows.Table.$$delete(state.addresses, key));
232
196
  Object.entries(state.history).forEach(param => {
233
197
  state.history[param[0]] = param[1].filter(row => row.checkpointId <= targetCheckpointId);
234
198
  });
235
199
  }
236
200
 
237
- function writeBatch(state, batch, rollback, isInReorgThreshold, config, updatedEntities, updatedEffectsCache, chainMetaData) {
201
+ function writeBatch(state, batch, rollback, isInReorgThreshold, config, updatedEntities, registeredAddresses, updatedEffectsCache, chainMetaData) {
238
202
  let shouldSaveHistory = Config.shouldSaveHistory(config, isInReorgThreshold);
239
203
  if (rollback !== undefined) {
240
- applyRollback(state, rollback.targetCheckpointId);
204
+ applyRollback(state, rollback.targetCheckpointId, rollback.rolledBackAddresses);
241
205
  }
206
+ registeredAddresses.forEach(param => AddressRows.Table.insert(state.addresses, param.row));
242
207
  let diffCheckpointId = Stdlib_Option.map(rollback, param => param.diffCheckpointId);
243
208
  let isDiff = change => {
244
209
  if (diffCheckpointId !== undefined) {
@@ -431,12 +396,12 @@ function toStorage(state, config) {
431
396
  return {
432
397
  name: "memory",
433
398
  isInitialized: async () => state.isInitialized,
434
- initialize: async (chainConfigsOpt, entitiesOpt, $staropt$star, envioInfo) => {
399
+ initialize: async (chainConfigsOpt, entitiesOpt, $staropt$star, contractMapping, envioInfo) => {
435
400
  let chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
436
401
  let entities = entitiesOpt !== undefined ? entitiesOpt : [];
437
402
  $staropt$star !== undefined;
438
403
  registerEntities(state, entities);
439
- seedIndexingAddresses(state, chainConfigs);
404
+ seedConfigAddresses(state, chainConfigs, contractMapping, config.ecosystem.name);
440
405
  chainConfigs.forEach(chainConfig => {
441
406
  state.chains[ChainId.toString(chainConfig.id)] = {
442
407
  id: chainConfig.id,
@@ -453,9 +418,9 @@ function toStorage(state, config) {
453
418
  });
454
419
  state.envioInfo = envioInfo;
455
420
  state.isInitialized = true;
456
- return toInitialState(state, true);
421
+ return toInitialState(state, true, contractMapping);
457
422
  },
458
- resumeInitialState: async () => toInitialState(state, false),
423
+ resumeInitialState: async () => toInitialState(state, false, config.contractMapping),
459
424
  loadOrThrow: async (filter, table) => handleLoad(state, table.tableName, filter),
460
425
  ensureQueryIndexes: async (param, param$1) => {},
461
426
  ensureSchemaIndexes: async param => {},
@@ -470,15 +435,14 @@ function toStorage(state, config) {
470
435
  },
471
436
  dumpEffectCache: async () => {},
472
437
  reset: async () => {
473
- let clear = dict => {
474
- Object.keys(dict).forEach(key => Utils.Dict.deleteInPlace(dict, key));
475
- };
438
+ let clear = Utils.Dict.clearInPlace;
476
439
  clear(state.entities);
477
440
  clear(state.history);
478
441
  clear(state.chains);
479
442
  clear(state.effectCache);
480
443
  clear(state.cache);
481
444
  state.checkpoints = [];
445
+ AddressRows.Table.clear(state.addresses);
482
446
  state.envioInfo = undefined;
483
447
  state.isInitialized = false;
484
448
  },
@@ -539,7 +503,7 @@ function toStorage(state, config) {
539
503
  }),
540
504
  getRollbackProgressDiff: async rollbackTargetCheckpointId => getRollbackProgressDiff(state, rollbackTargetCheckpointId),
541
505
  getRollbackData: async (entityConfig, rollbackTargetCheckpointId) => getRollbackData(state, entityConfig, rollbackTargetCheckpointId),
542
- writeBatch: async (batch, rollback, isInReorgThreshold, param, param$1, updatedEffectsCache, updatedEntities, chainMetaData, param$2) => writeBatch(state, batch, rollback, isInReorgThreshold, config, updatedEntities, updatedEffectsCache, chainMetaData),
506
+ writeBatch: async (batch, rollback, isInReorgThreshold, param, param$1, updatedEffectsCache, updatedEntities, registeredAddresses, chainMetaData, param$2) => writeBatch(state, batch, rollback, isInReorgThreshold, config, updatedEntities, registeredAddresses, updatedEffectsCache, chainMetaData),
543
507
  close: async () => {}
544
508
  };
545
509
  }
@@ -601,9 +565,8 @@ export {
601
565
  getEntityDict,
602
566
  getHistory,
603
567
  registerEntities,
604
- seedIndexingAddresses,
605
- toIndexingAddress,
606
- getIndexingAddressesByChain,
568
+ seedConfigAddresses,
569
+ addressRowsByChain,
607
570
  toInitialChainStates,
608
571
  committedCheckpointId,
609
572
  reorgCheckpoints,
package/src/Metrics.res CHANGED
@@ -12,6 +12,8 @@ type chainMetrics = {
12
12
  startBlock: int,
13
13
  endBlock: option<int>,
14
14
  numAddresses: int,
15
+ // Per-contract registration counts, in the chain's contract-id order.
16
+ addressesByContract: array<(string, int)>,
15
17
  isReady: bool,
16
18
  // Raw source height, unlike knownHeight which is clamped to endBlock.
17
19
  sourceBlockNumber: int,
@@ -694,11 +696,23 @@ let renderMetrics = (b: builder, metrics: t) => {
694
696
  )
695
697
  b->series(
696
698
  ~name="envio_indexing_addresses",
697
- ~help="The number of addresses indexed on chain. Includes both static and dynamic addresses.",
699
+ ~help="The number of address registrations on chain, static and dynamic. An address shared by N contracts counts N times.",
698
700
  ~kind="gauge",
699
701
  ~entries=chains,
700
702
  ~value=m => m.numAddresses->Int.toFloat,
701
703
  )
704
+ b->series(
705
+ ~name="envio_indexing_contract_addresses",
706
+ ~help="The number of address registrations per contract on chain, static and dynamic. An address shared by N contracts counts N times.",
707
+ ~kind="gauge",
708
+ ~entries=metrics.chains->Array.flatMap(m =>
709
+ m.addressesByContract->Array.map(((contract, count)) => (
710
+ `{chainId="${m.chainId->ChainId.toString}",contract="${contract->escapeLabelValue}"}`,
711
+ count,
712
+ ))
713
+ ),
714
+ ~value=count => count->Int.toFloat,
715
+ )
702
716
  }
703
717
 
704
718
  let contentType = "text/plain; version=0.0.4; charset=utf-8"
@@ -229,7 +229,11 @@ function renderMetrics(b, metrics) {
229
229
  series(b, "envio_storage_load_size", "Cumulative number of records loaded from storage during the indexing process.", "counter", storageLoads, s => s.size);
230
230
  series(b, "envio_storage_write_seconds", "Cumulative time spent writing batch data to storage.", "counter", storageWrites, s => s.seconds);
231
231
  series(b, "envio_storage_write_total", "Cumulative number of successful storage write operations during the indexing process.", "counter", storageWrites, s => s.count);
232
- series(b, "envio_indexing_addresses", "The number of addresses indexed on chain. Includes both static and dynamic addresses.", "gauge", chains, m => m.numAddresses);
232
+ series(b, "envio_indexing_addresses", "The number of address registrations on chain, static and dynamic. An address shared by N contracts counts N times.", "gauge", chains, m => m.numAddresses);
233
+ series(b, "envio_indexing_contract_addresses", "The number of address registrations per contract on chain, static and dynamic. An address shared by N contracts counts N times.", "gauge", metrics.chains.flatMap(m => m.addressesByContract.map(param => [
234
+ `{chainId="` + ChainId.toString(m.chainId) + `",contract="` + escapeLabelValue(param[0]) + `"}`,
235
+ param[1]
236
+ ])), count => count);
233
237
  }
234
238
 
235
239
  function collect(metrics) {
@@ -27,22 +27,25 @@ type initialChainState = {
27
27
  numEventsProcessed: float,
28
28
  firstEventBlockNumber: option<int>,
29
29
  timestampCaughtUpToHeadOrEndblock: option<Date.t>,
30
- indexingAddresses: array<Internal.indexingAddress>,
30
+ // Every address the chain indexes, columnar — config-declared and dynamically
31
+ // registered alike. The chain's address store seeds straight from it.
32
+ addressRows: AddressRows.seedRows,
31
33
  sourceBlockNumber: int,
32
34
  }
33
35
 
34
36
  type initialState = {
35
37
  cleanRun: bool,
38
+ // On a resume this is what the database holds, not what the config would
39
+ // derive — the ids must never reshuffle under stored rows.
40
+ contractMapping: ContractMapping.t,
41
+ // Public config snapshot, restored with the address rows. None when
42
+ // envio_info or envio_contracts is missing.
43
+ envioInfo: option<JSON.t>,
36
44
  cache: dict<effectCacheRecord>,
37
45
  chains: array<initialChainState>,
38
46
  checkpointId: Internal.checkpointId,
39
47
  // Needed to keep reorg detection logic between restarts
40
48
  reorgCheckpoints: array<Internal.reorgCheckpoint>,
41
- // Public config snapshot read from envio_info, used by `Persistence.init`
42
- // to compat-check a resume against the running config. None when the
43
- // schema pre-dates envio_info or the row is missing — `init` treats that
44
- // as a version mismatch.
45
- envioInfo: option<JSON.t>,
46
49
  }
47
50
 
48
51
  // Carries the already-resolved cache address (`table`) rather than an effect +
@@ -58,6 +61,9 @@ type updatedEffectCache = {
58
61
  type rollback = {
59
62
  targetCheckpointId: Internal.checkpointId,
60
63
  diffCheckpointId: Internal.checkpointId,
64
+ // The address registrations the rollback dropped, as the chains' address
65
+ // stores resolved them. Deleted by primary key in the same transaction.
66
+ rolledBackAddresses: array<AddressRows.key>,
61
67
  // Last valid block per chain affected by the rollback. Read by
62
68
  // `RollbackCommit.fire` once the diff is durably written.
63
69
  progressBlockNumberByChainId: dict<int>,
@@ -92,6 +98,7 @@ type storage = {
92
98
  ~chainConfigs: array<Config.chain>=?,
93
99
  ~entities: array<Internal.entityConfig>=?,
94
100
  ~enums: array<Table.enumConfig<Table.enum>>=?,
101
+ ~contractMapping: ContractMapping.t,
95
102
  ~envioInfo: JSON.t,
96
103
  ) => promise<initialState>,
97
104
  resumeInitialState: unit => promise<initialState>,
@@ -163,6 +170,8 @@ type storage = {
163
170
  ~allEntities: array<Internal.entityConfig>,
164
171
  ~updatedEffectsCache: array<updatedEffectCache>,
165
172
  ~updatedEntities: array<updatedEntity>,
173
+ // Addresses this batch registered, with the checkpoint that covers them.
174
+ ~registeredAddresses: array<AddressRows.staged>,
166
175
  // Chain metadata stale since the last write, persisted in the same
167
176
  // transaction so it never races the batch write.
168
177
  ~chainMetaData: option<dict<InternalTable.Chains.metaFields>>,
@@ -196,7 +205,7 @@ let make = (
196
205
  ~allEnums,
197
206
  ~storage,
198
207
  ) => {
199
- let allEntities = userEntities->Array.concat([InternalTable.EnvioAddresses.entityConfig])
208
+ let allEntities = userEntities
200
209
  let allEnums =
201
210
  allEnums->Array.concat([EntityHistory.RowAction.config->Table.fromGenericEnumConfig])
202
211
  {
@@ -209,7 +218,15 @@ let make = (
209
218
  }
210
219
 
211
220
  let init = {
212
- async (persistence, ~chainConfigs, ~envioInfo, ~resetCommand, ~runCommand, ~reset=false) => {
221
+ async (
222
+ persistence,
223
+ ~chainConfigs,
224
+ ~contractMapping,
225
+ ~envioInfo,
226
+ ~resetCommand,
227
+ ~runCommand,
228
+ ~reset=false,
229
+ ) => {
213
230
  try {
214
231
  let shouldRun = switch persistence.storageStatus {
215
232
  | Unknown => true
@@ -231,6 +248,7 @@ let init = {
231
248
  ~entities=persistence.allEntities,
232
249
  ~enums=persistence.allEnums,
233
250
  ~chainConfigs,
251
+ ~contractMapping,
234
252
  ~envioInfo,
235
253
  )
236
254
  Logging.info(`The indexer storage is ready. Starting indexing!`)
@@ -245,17 +263,10 @@ let init = {
245
263
  ) {
246
264
  Logging.info(`Found existing indexer storage. Resuming indexing state...`)
247
265
  let initialState = await persistence.storage.resumeInitialState()
248
- // Compat-check the running config against what was stored on the
249
- // last successful initialize. None means the schema pre-dates
250
- // envio_info (or the row was wiped out-of-band) and we can't
251
- // compare — treat it as a version mismatch.
252
266
  let changedPaths = switch initialState.envioInfo {
253
- | None => ["envio info is missing — storage initialized by an older envio"]
267
+ | None => ["storage was initialized by an older envio version"]
254
268
  | Some(stored) => Config.diffPaths(~stored, ~current=envioInfo)
255
269
  }
256
- // `storage.clickhouse` is serialized as a plain bool by the
257
- // public config (see Rust `StorageConfig`), so probe for
258
- // `Boolean(true)`, not an object.
259
270
  let hasClickhouse = switch envioInfo {
260
271
  | Object(d) =>
261
272
  switch d->Dict.get("storage") {
@@ -269,6 +280,9 @@ let init = {
269
280
  | _ => false
270
281
  }
271
282
  Config.throwIfIncompatible(changedPaths, ~resetCommand, ~runCommand, ~hasClickhouse)
283
+ if !(initialState.contractMapping->ContractMapping.isEqual(contractMapping)) {
284
+ Config.throwIfIncompatible(["contracts"], ~resetCommand, ~runCommand, ~hasClickhouse)
285
+ }
272
286
  persistence.storageStatus = Ready(initialState)
273
287
  let progress = Dict.make()
274
288
  initialState.chains->Array.forEach(c => {
@@ -5,23 +5,23 @@ import * as Logging from "./Logging.res.mjs";
5
5
  import * as EntityHistory from "./db/EntityHistory.res.mjs";
6
6
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
7
7
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
8
+ import * as ContractMapping from "./ContractMapping.res.mjs";
8
9
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
9
10
 
10
11
  let StorageError = /* @__PURE__ */Primitive_exceptions.create("Persistence.StorageError");
11
12
 
12
13
  function make(userEntities, allEnums, storage) {
13
- let allEntities = userEntities.concat([Config.EnvioAddresses.entityConfig]);
14
14
  let allEnums$1 = allEnums.concat([EntityHistory.RowAction.config]);
15
15
  return {
16
16
  userEntities: userEntities,
17
- allEntities: allEntities,
17
+ allEntities: userEntities,
18
18
  allEnums: allEnums$1,
19
19
  storageStatus: "Unknown",
20
20
  storage: storage
21
21
  };
22
22
  }
23
23
 
24
- async function init(persistence, chainConfigs, envioInfo, resetCommand, runCommand, resetOpt) {
24
+ async function init(persistence, chainConfigs, contractMapping, envioInfo, resetCommand, runCommand, resetOpt) {
25
25
  let reset = resetOpt !== undefined ? resetOpt : false;
26
26
  try {
27
27
  let promise = persistence.storageStatus;
@@ -49,7 +49,7 @@ async function init(persistence, chainConfigs, envioInfo, resetCommand, runComma
49
49
  };
50
50
  if (reset || !await persistence.storage.isInitialized()) {
51
51
  Logging.info(`Initializing the indexer storage...`);
52
- let initialState = await persistence.storage.initialize(chainConfigs, persistence.allEntities, persistence.allEnums, envioInfo);
52
+ let initialState = await persistence.storage.initialize(chainConfigs, persistence.allEntities, persistence.allEnums, contractMapping, envioInfo);
53
53
  Logging.info(`The indexer storage is ready. Starting indexing!`);
54
54
  persistence.storageStatus = {
55
55
  TAG: "Ready",
@@ -63,7 +63,7 @@ async function init(persistence, chainConfigs, envioInfo, resetCommand, runComma
63
63
  Logging.info(`Found existing indexer storage. Resuming indexing state...`);
64
64
  let initialState$1 = await persistence.storage.resumeInitialState();
65
65
  let stored = initialState$1.envioInfo;
66
- let changedPaths = stored !== undefined ? Config.diffPaths(stored, envioInfo) : ["envio info is missing — storage initialized by an older envio"];
66
+ let changedPaths = stored !== undefined ? Config.diffPaths(stored, envioInfo) : ["storage was initialized by an older envio version"];
67
67
  let hasClickhouse;
68
68
  if (typeof envioInfo === "object" && envioInfo !== null && !Array.isArray(envioInfo)) {
69
69
  let match$1 = envioInfo["storage"];
@@ -77,6 +77,9 @@ async function init(persistence, chainConfigs, envioInfo, resetCommand, runComma
77
77
  hasClickhouse = false;
78
78
  }
79
79
  Config.throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhouse);
80
+ if (!ContractMapping.isEqual(initialState$1.contractMapping, contractMapping)) {
81
+ Config.throwIfIncompatible(["contracts"], resetCommand, runCommand, hasClickhouse);
82
+ }
80
83
  persistence.storageStatus = {
81
84
  TAG: "Ready",
82
85
  _0: initialState$1