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
@@ -37,44 +37,19 @@ type testIndexerState = {
37
37
  // Store decoded entities (not JSON) for proper comparison operations
38
38
  entities: dict<dict<Internal.entity>>,
39
39
  entityConfigs: dict<Internal.entityConfig>,
40
+ addresses: AddressRows.Table.t,
41
+ contractMapping: ContractMapping.t,
40
42
  mutable processChanges: array<unknown>,
41
43
  }
42
44
 
43
- // Cast Internal.entity back to EnvioAddresses.t
44
- external castToEnvioAddresses: Internal.entity => InternalTable.EnvioAddresses.t = "%identity"
45
+ let addressRowsByChain = (state: testIndexerState) =>
46
+ state.addresses->AddressRows.Table.groupByChain
45
47
 
46
- let toIndexingAddress = (dc: InternalTable.EnvioAddresses.t): Internal.indexingAddress => {
47
- address: dc->Config.EnvioAddresses.getAddress,
48
- contractName: dc.contractName,
49
- registrationBlock: dc.registrationBlock,
50
- }
51
-
52
- // All indexing addresses (config-seeded + dynamically registered) grouped by
53
- // chain id string, derived from the envio_addresses entities.
54
- let getIndexingAddressesByChain = (state: testIndexerState): dict<
55
- array<Internal.indexingAddress>,
56
- > => {
57
- let byChain = Dict.make()
58
- switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
59
- | Some(dcDict) =>
60
- dcDict
61
- ->Dict.valuesToArray
62
- ->Array.forEach(entity => {
63
- let dc = entity->castToEnvioAddresses
64
- let chainIdStr = dc.chainId->ChainId.toString
65
- let contracts = switch byChain->Dict.get(chainIdStr) {
66
- | Some(arr) => arr
67
- | None =>
68
- let arr = []
69
- byChain->Dict.set(chainIdStr, arr)
70
- arr
71
- }
72
- contracts->Array.push(dc->toIndexingAddress)->ignore
73
- })
74
- | None => ()
75
- }
76
- byChain
77
- }
48
+ let renderRows = (rows: array<AddressRows.row>, ~config: Config.t) =>
49
+ rows->AddressRows.render(
50
+ ~ecosystem=(config.ecosystem.name :> string),
51
+ ~shouldChecksum=!config.lowercaseAddresses,
52
+ )
78
53
 
79
54
  // Rows of a per-chain entity are keyed per (chain, id): the same id exists
80
55
  // independently on every chain.
@@ -125,7 +100,9 @@ let handleLoad = (state: testIndexerState, ~tableName: string, ~filter: EntityFi
125
100
 
126
101
  let handleWriteBatch = (
127
102
  state: testIndexerState,
103
+ ~config: Config.t,
128
104
  ~updatedEntities: array<Persistence.updatedEntity>,
105
+ ~registeredAddresses: array<AddressRows.staged>,
129
106
  ~checkpointIds: array<bigint>,
130
107
  ~checkpointChainIds: array<ChainId.t>,
131
108
  ~checkpointBlockNumbers: array<int>,
@@ -135,6 +112,22 @@ let handleWriteBatch = (
135
112
  // checkpointId -> entityName -> entityChange
136
113
  let changesByCheckpoint: dict<dict<entityChange>> = Dict.make()
137
114
 
115
+ // checkpointId -> the addresses that checkpoint registered, rendered for the
116
+ // change log. Rendering is the Rust codec's job, so the rows keep their keys
117
+ // right up to here.
118
+ let addressesByCheckpoint: dict<array<{"address": Address.t, "contract": string}>> = Dict.make()
119
+ let rendered = registeredAddresses->Array.map(({row}) => row)->renderRows(~config)
120
+ registeredAddresses->Array.forEachWithIndex(({row, checkpointId}, idx) => {
121
+ state.addresses->AddressRows.Table.insert(row)
122
+ addressesByCheckpoint->Utils.Dict.push(
123
+ checkpointId->BigInt.toString,
124
+ {
125
+ "address": rendered->Array.getUnsafe(idx),
126
+ "contract": state.contractMapping->ContractMapping.nameOfOrThrow(row.contractId),
127
+ },
128
+ )
129
+ })
130
+
138
131
  updatedEntities->Array.forEach(({entityConfig, scope, changes}: Persistence.updatedEntity) => {
139
132
  let entityName = entityConfig.name
140
133
  // The scope is what makes a per-chain row identifiable, so it's stamped
@@ -210,43 +203,33 @@ let handleWriteBatch = (
210
203
 
211
204
  // Add entity changes for this checkpoint
212
205
  let checkpointKey = checkpointId->BigInt.toString
206
+ switch addressesByCheckpoint->Utils.Dict.dangerouslyGetNonOption(checkpointKey) {
207
+ | Some(rendered) =>
208
+ let addressesObj: dict<unknown> = Dict.make()
209
+ addressesObj->Dict.set(
210
+ "sets",
211
+ rendered->(Utils.magic: array<{"address": Address.t, "contract": string}> => unknown),
212
+ )
213
+ change->Dict.set("addresses", addressesObj->(Utils.magic: dict<unknown> => unknown))
214
+ | None => ()
215
+ }
213
216
  switch changesByCheckpoint->Dict.get(checkpointKey) {
214
217
  | Some(entityChanges) =>
215
218
  entityChanges
216
219
  ->Dict.toArray
217
220
  ->Array.forEach(((entityName, {sets, deleted})) => {
218
- // Transform envio_addresses to addresses with simplified structure
219
- if entityName === InternalTable.EnvioAddresses.name {
220
- let entityObj: dict<unknown> = Dict.make()
221
- if sets->Array.length > 0 {
222
- // Transform sets to simplified {address, contract} objects
223
- let simplifiedSets = sets->Array.map(entity => {
224
- let dc = entity->Utils.magic->castToEnvioAddresses
225
- {"address": dc->Config.EnvioAddresses.getAddress, "contract": dc.contractName}
226
- })
227
- entityObj->Dict.set(
228
- "sets",
229
- simplifiedSets->(
230
- Utils.magic: array<{"address": Address.t, "contract": string}> => unknown
231
- ),
232
- )
233
- }
234
- // Note: deleted is not relevant for addresses since we use address string directly
235
- change->Dict.set("addresses", entityObj->(Utils.magic: dict<unknown> => unknown))
236
- } else {
237
- let entityObj: dict<unknown> = Dict.make()
238
- if sets->Array.length > 0 {
239
- entityObj->Dict.set("sets", sets->(Utils.magic: array<unknown> => unknown))
240
- }
241
- if deleted->Array.length > 0 {
242
- entityObj->Dict.set("deleted", deleted->(Utils.magic: array<EntityId.t> => unknown))
243
- }
244
- // Match the capitalized entity accessor the generated change types expose.
245
- change->Dict.set(
246
- entityName->Utils.String.capitalize,
247
- entityObj->(Utils.magic: dict<unknown> => unknown),
248
- )
221
+ let entityObj: dict<unknown> = Dict.make()
222
+ if sets->Array.length > 0 {
223
+ entityObj->Dict.set("sets", sets->(Utils.magic: array<unknown> => unknown))
224
+ }
225
+ if deleted->Array.length > 0 {
226
+ entityObj->Dict.set("deleted", deleted->(Utils.magic: array<EntityId.t> => unknown))
249
227
  }
228
+ // Match the capitalized entity accessor the generated change types expose.
229
+ change->Dict.set(
230
+ entityName->Utils.String.capitalize,
231
+ entityObj->(Utils.magic: dict<unknown> => unknown),
232
+ )
250
233
  })
251
234
  | None => ()
252
235
  }
@@ -260,7 +243,8 @@ let handleWriteBatch = (
260
243
  let makeInitialState = (
261
244
  ~config: Config.t,
262
245
  ~processConfigChains: dict<chainConfig>,
263
- ~indexingAddressesByChain: dict<array<Internal.indexingAddress>>,
246
+ ~addressRowsByChain: dict<AddressRows.seedRows>,
247
+ ~contractMapping: ContractMapping.t,
264
248
  ): Persistence.initialState => {
265
249
  let chainKeys = processConfigChains->Dict.keysToArray
266
250
  let chains = chainKeys->Array.map(chainIdStr => {
@@ -271,7 +255,10 @@ let makeInitialState = (
271
255
  }
272
256
 
273
257
  let processChainConfig = processConfigChains->Dict.getUnsafe(chainIdStr)
274
- let indexingAddresses = indexingAddressesByChain->Dict.get(chainIdStr)->Option.getOr([])
258
+ let addressRows =
259
+ addressRowsByChain
260
+ ->Utils.Dict.dangerouslyGetNonOption(chainIdStr)
261
+ ->Option.getOr(AddressRows.emptySeedRows())
275
262
  {
276
263
  Persistence.id: chain,
277
264
  startBlock: processChainConfig.startBlock,
@@ -282,17 +269,18 @@ let makeInitialState = (
282
269
  numEventsProcessed: 0.,
283
270
  firstEventBlockNumber: None,
284
271
  timestampCaughtUpToHeadOrEndblock: None,
285
- indexingAddresses,
272
+ addressRows,
286
273
  }
287
274
  })
288
275
 
289
276
  {
290
277
  cleanRun: true,
278
+ contractMapping,
279
+ envioInfo: Some(JSON.Encode.object(Dict.make())),
291
280
  cache: Dict.make(),
292
281
  chains,
293
282
  checkpointId: InternalTable.Checkpoints.initialCheckpointId,
294
283
  reorgCheckpoints: [],
295
- envioInfo: Some(Config.getPublicConfigJson()->Config.stripSensitiveData),
296
284
  }
297
285
  }
298
286
 
@@ -591,7 +579,13 @@ let makeInMemoryStorage = (~state: testIndexerState): Persistence.storage => {
591
579
  // The runner injects the config-derived initial state by setting
592
580
  // `persistence.storageStatus = Ready(...)` directly, bypassing `Persistence.init`,
593
581
  // so neither of these is reached.
594
- initialize: async (~chainConfigs as _=?, ~entities as _=?, ~enums as _=?, ~envioInfo as _) =>
582
+ initialize: async (
583
+ ~chainConfigs as _=?,
584
+ ~entities as _=?,
585
+ ~enums as _=?,
586
+ ~contractMapping as _,
587
+ ~envioInfo as _,
588
+ ) =>
595
589
  JsError.throwWithMessage(
596
590
  "TestIndexer: initialize should not be called; the initial state is derived from config.",
597
591
  ),
@@ -611,15 +605,18 @@ let makeInMemoryStorage = (~state: testIndexerState): Persistence.storage => {
611
605
  ~batch,
612
606
  ~rollback as _,
613
607
  ~isInReorgThreshold as _,
614
- ~config as _,
608
+ ~config,
615
609
  ~allEntities as _,
616
610
  ~updatedEffectsCache as _,
617
611
  ~updatedEntities,
612
+ ~registeredAddresses,
618
613
  ~chainMetaData as _,
619
614
  ~onWrite as _,
620
615
  ) =>
621
616
  state->handleWriteBatch(
617
+ ~config,
622
618
  ~updatedEntities,
619
+ ~registeredAddresses,
623
620
  ~checkpointIds=batch.checkpointIds,
624
621
  ~checkpointChainIds=batch.checkpointChainIds,
625
622
  ~checkpointBlockNumbers=batch.checkpointBlockNumbers,
@@ -688,7 +685,7 @@ let getRegistrations = (~config) =>
688
685
 
689
686
  let createTestIndexer = (): t<'processConfig> => {
690
687
  let config = Config.load()
691
- let allEntities = config.allEntities
688
+ let allEntities = config.userEntities
692
689
  let entities = Dict.make()
693
690
  let entityConfigs = Dict.make()
694
691
  allEntities->Array.forEach(entityConfig => {
@@ -696,32 +693,19 @@ let createTestIndexer = (): t<'processConfig> => {
696
693
  entityConfigs->Dict.set(entityConfig.name, entityConfig)
697
694
  })
698
695
 
699
- // Populate config addresses into the entity dict, mirroring PgStorage.initialize
700
- let envioAddressesDict = entities->Dict.getUnsafe(InternalTable.EnvioAddresses.name)
701
- config.chainMap
702
- ->ChainMap.values
703
- ->Array.forEach(chainConfig => {
704
- chainConfig.contracts->Array.forEach(contract => {
705
- contract.addresses->Array.forEach(
706
- address => {
707
- let entity: InternalTable.EnvioAddresses.t = {
708
- id: Config.EnvioAddresses.makeId(~chainId=chainConfig.id, ~address),
709
- chainId: chainConfig.id,
710
- contractName: contract.name,
711
- registrationBlock: -1,
712
- registrationLogIndex: -1,
713
- }
714
- envioAddressesDict->Dict.set(entity.id, entity->Config.EnvioAddresses.castToInternal)
715
- },
716
- )
717
- })
718
- })
696
+ let chainConfigs = config.chainMap->ChainMap.values
697
+ let contractMapping = config.contractMapping
698
+ let ecosystem = config.ecosystem.name
699
+ let addresses = AddressRows.Table.make()
700
+ addresses->ChainState.seedConfigAddresses(~chainConfigs, ~ecosystem, ~contractMapping)
719
701
 
720
702
  let state = {
721
703
  processInProgress: false,
722
704
  progressBlockByChain: Dict.make(),
723
705
  entities,
724
706
  entityConfigs,
707
+ addresses,
708
+ contractMapping,
725
709
  processChanges: [],
726
710
  }
727
711
 
@@ -744,19 +728,16 @@ let createTestIndexer = (): t<'processConfig> => {
744
728
  // Build entity operations for each user entity
745
729
  let entityOpsDict: dict<entityOperations> = Dict.make()
746
730
  allEntities->Array.forEach(entityConfig => {
747
- // Only create ops for user entities (not internal tables like envio_addresses)
748
- if entityConfig.name !== InternalTable.EnvioAddresses.name {
749
- entityOpsDict->Dict.set(
750
- entityConfig.name,
751
- {
752
- get: makeEntityGet(~state, ~entityConfig),
753
- getAll: makeEntityGetAll(~state, ~entityConfig),
754
- getWhere: makeEntityGetWhere(~state, ~entityConfig),
755
- getOrThrow: makeEntityGetOrThrow(~state, ~entityConfig),
756
- set: makeEntitySet(~state, ~entityConfig),
757
- },
758
- )
759
- }
731
+ entityOpsDict->Dict.set(
732
+ entityConfig.name,
733
+ {
734
+ get: makeEntityGet(~state, ~entityConfig),
735
+ getAll: makeEntityGetAll(~state, ~entityConfig),
736
+ getWhere: makeEntityGetWhere(~state, ~entityConfig),
737
+ getOrThrow: makeEntityGetOrThrow(~state, ~entityConfig),
738
+ set: makeEntitySet(~state, ~entityConfig),
739
+ },
740
+ )
760
741
  })
761
742
 
762
743
  // Build chain info from config (similar to Main.getGlobalIndexer but static)
@@ -799,10 +780,11 @@ let createTestIndexer = (): t<'processConfig> => {
799
780
  `Cannot access ${contract.name}.addresses while indexer.process() is running. ` ++ "Wait for process() to complete before reading contract addresses.",
800
781
  )
801
782
  }
802
- getIndexingAddressesByChain(state)
803
- ->Dict.get(chainConfig.id->ChainId.toString)
804
- ->Option.getOr([])
805
- ->Array.filterMap(ia => ia.contractName === contract.name ? Some(ia.address) : None)
783
+ let contractId = state.contractMapping->ContractMapping.idOfOrThrow(contract.name)
784
+ state.addresses
785
+ ->AddressRows.Table.rows
786
+ ->Array.filter(row => row.chainId === chainConfig.id && row.contractId === contractId)
787
+ ->renderRows(~config)
806
788
  },
807
789
  },
808
790
  )
@@ -899,11 +881,11 @@ let createTestIndexer = (): t<'processConfig> => {
899
881
  // by earlier ones.
900
882
  let chains: dict<chainConfig> = Dict.make()
901
883
  chains->Dict.set(chainIdStr, processChainConfig)
902
- let indexingAddressesByChain = getIndexingAddressesByChain(state)
903
884
  let initialState = makeInitialState(
904
885
  ~config,
905
886
  ~processConfigChains=chains,
906
- ~indexingAddressesByChain,
887
+ ~addressRowsByChain=addressRowsByChain(state),
888
+ ~contractMapping=state.contractMapping,
907
889
  )
908
890
 
909
891
  // No endBlock means auto-exit mode: process one block checkpoint at a
@@ -9,13 +9,14 @@ import * as Logging from "./Logging.res.mjs";
9
9
  import * as ChainMap from "./ChainMap.res.mjs";
10
10
  import * as EntityId from "./EntityId.res.mjs";
11
11
  import * as Internal from "./Internal.res.mjs";
12
+ import * as ChainState from "./ChainState.res.mjs";
12
13
  import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
14
+ import * as AddressRows from "./AddressRows.res.mjs";
13
15
  import * as IndexerLoop from "./IndexerLoop.res.mjs";
14
16
  import * as Persistence from "./Persistence.res.mjs";
15
17
  import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
16
18
  import * as EntityFilter from "./db/EntityFilter.res.mjs";
17
19
  import * as IndexerState from "./IndexerState.res.mjs";
18
- import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
19
20
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
20
21
  import * as HandlerLoader from "./HandlerLoader.res.mjs";
21
22
  import * as InternalTable from "./db/InternalTable.res.mjs";
@@ -24,37 +25,17 @@ import * as SimulateItems from "./SimulateItems.res.mjs";
24
25
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
25
26
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
26
27
  import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
28
+ import * as ContractMapping from "./ContractMapping.res.mjs";
27
29
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
28
30
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
29
31
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
30
32
 
31
- function toIndexingAddress(dc) {
32
- return {
33
- address: Config.EnvioAddresses.getAddress(dc),
34
- contractName: dc.contract_name,
35
- registrationBlock: dc.registration_block
36
- };
33
+ function addressRowsByChain(state) {
34
+ return AddressRows.Table.groupByChain(state.addresses);
37
35
  }
38
36
 
39
- function getIndexingAddressesByChain(state) {
40
- let byChain = {};
41
- let dcDict = state.entities[Config.EnvioAddresses.name];
42
- if (dcDict !== undefined) {
43
- Object.values(dcDict).forEach(entity => {
44
- let chainIdStr = ChainId.toString(entity.chain_id);
45
- let arr = byChain[chainIdStr];
46
- let contracts;
47
- if (arr !== undefined) {
48
- contracts = arr;
49
- } else {
50
- let arr$1 = [];
51
- byChain[chainIdStr] = arr$1;
52
- contracts = arr$1;
53
- }
54
- contracts.push(toIndexingAddress(entity));
55
- });
56
- }
57
- return byChain;
37
+ function renderRows(rows, config) {
38
+ return AddressRows.render(rows, config.ecosystem.name, !config.lowercaseAddresses);
58
39
  }
59
40
 
60
41
  function rowKey(scope, entityId) {
@@ -88,8 +69,18 @@ function handleLoad(state, tableName, filter) {
88
69
  }
89
70
  }
90
71
 
91
- function handleWriteBatch(state, updatedEntities, checkpointIds, checkpointChainIds, checkpointBlockNumbers, checkpointEventsProcessed) {
72
+ function handleWriteBatch(state, config, updatedEntities, registeredAddresses, checkpointIds, checkpointChainIds, checkpointBlockNumbers, checkpointEventsProcessed) {
92
73
  let changesByCheckpoint = {};
74
+ let addressesByCheckpoint = {};
75
+ let rendered = renderRows(registeredAddresses.map(param => param.row), config);
76
+ registeredAddresses.forEach((param, idx) => {
77
+ let row = param.row;
78
+ AddressRows.Table.insert(state.addresses, row);
79
+ Utils.Dict.push(addressesByCheckpoint, param.checkpointId.toString(), {
80
+ address: rendered[idx],
81
+ contract: ContractMapping.nameOfOrThrow(state.contractMapping, row.contractId)
82
+ });
83
+ });
93
84
  updatedEntities.forEach(param => {
94
85
  let scope = param.scope;
95
86
  let entityConfig = param.entityConfig;
@@ -151,40 +142,33 @@ function handleWriteBatch(state, updatedEntities, checkpointIds, checkpointChain
151
142
  change["chainId"] = checkpointChainIds[i];
152
143
  change["eventsProcessed"] = checkpointEventsProcessed[i];
153
144
  let checkpointKey = checkpointId.toString();
145
+ let rendered$1 = addressesByCheckpoint[checkpointKey];
146
+ if (rendered$1 !== undefined) {
147
+ let addressesObj = {};
148
+ addressesObj["sets"] = rendered$1;
149
+ change["addresses"] = addressesObj;
150
+ }
154
151
  let entityChanges = changesByCheckpoint[checkpointKey];
155
152
  if (entityChanges !== undefined) {
156
153
  Object.entries(entityChanges).forEach(param => {
157
154
  let match = param[1];
158
155
  let deleted = match.deleted;
159
156
  let sets = match.sets;
160
- let entityName = param[0];
161
- if (entityName === Config.EnvioAddresses.name) {
162
- let entityObj = {};
163
- if (sets.length !== 0) {
164
- let simplifiedSets = sets.map(entity => ({
165
- address: Config.EnvioAddresses.getAddress(entity),
166
- contract: entity.contract_name
167
- }));
168
- entityObj["sets"] = simplifiedSets;
169
- }
170
- change["addresses"] = entityObj;
171
- return;
172
- }
173
- let entityObj$1 = {};
157
+ let entityObj = {};
174
158
  if (sets.length !== 0) {
175
- entityObj$1["sets"] = sets;
159
+ entityObj["sets"] = sets;
176
160
  }
177
161
  if (deleted.length !== 0) {
178
- entityObj$1["deleted"] = deleted;
162
+ entityObj["deleted"] = deleted;
179
163
  }
180
- change[Utils.$$String.capitalize(entityName)] = entityObj$1;
164
+ change[Utils.$$String.capitalize(param[0])] = entityObj;
181
165
  });
182
166
  }
183
167
  state.processChanges.push(change);
184
168
  }
185
169
  }
186
170
 
187
- function makeInitialState(config, processConfigChains, indexingAddressesByChain) {
171
+ function makeInitialState(config, processConfigChains, addressRowsByChain, contractMapping) {
188
172
  let chainKeys = Object.keys(processConfigChains);
189
173
  let chains = chainKeys.map(chainIdStr => {
190
174
  let chain = ChainId.normalizeOrThrow(chainIdStr);
@@ -192,7 +176,7 @@ function makeInitialState(config, processConfigChains, indexingAddressesByChain)
192
176
  Stdlib_JsError.throwWithMessage(`Chain ` + chainIdStr + ` is not configured in config.yaml`);
193
177
  }
194
178
  let processChainConfig = processConfigChains[chainIdStr];
195
- let indexingAddresses = Stdlib_Option.getOr(indexingAddressesByChain[chainIdStr], []);
179
+ let addressRows = Stdlib_Option.getOr(addressRowsByChain[chainIdStr], AddressRows.emptySeedRows());
196
180
  return {
197
181
  id: chain,
198
182
  startBlock: processChainConfig.startBlock,
@@ -202,17 +186,18 @@ function makeInitialState(config, processConfigChains, indexingAddressesByChain)
202
186
  numEventsProcessed: 0,
203
187
  firstEventBlockNumber: undefined,
204
188
  timestampCaughtUpToHeadOrEndblock: undefined,
205
- indexingAddresses: indexingAddresses,
189
+ addressRows: addressRows,
206
190
  sourceBlockNumber: Stdlib_Option.getOr(processChainConfig.endBlock, 0)
207
191
  };
208
192
  });
209
193
  return {
210
194
  cleanRun: true,
195
+ contractMapping: contractMapping,
196
+ envioInfo: {},
211
197
  cache: {},
212
198
  chains: chains,
213
199
  checkpointId: InternalTable.Checkpoints.initialCheckpointId,
214
- reorgCheckpoints: [],
215
- envioInfo: Config.stripSensitiveData(Config.getPublicConfigJson())
200
+ reorgCheckpoints: []
216
201
  };
217
202
  }
218
203
 
@@ -399,7 +384,7 @@ function makeInMemoryStorage(state) {
399
384
  return {
400
385
  name: "test-inmemory",
401
386
  isInitialized: async () => true,
402
- initialize: async (param, param$1, param$2, param$3) => Stdlib_JsError.throwWithMessage("TestIndexer: initialize should not be called; the initial state is derived from config."),
387
+ initialize: async (param, param$1, param$2, param$3, param$4) => Stdlib_JsError.throwWithMessage("TestIndexer: initialize should not be called; the initial state is derived from config."),
403
388
  resumeInitialState: async () => Stdlib_JsError.throwWithMessage("TestIndexer: resumeInitialState should not be called; the initial state is derived from config."),
404
389
  loadOrThrow: async (filter, table) => handleLoad(state, table.tableName, filter),
405
390
  ensureQueryIndexes: async (param, param$1) => {},
@@ -413,7 +398,7 @@ function makeInMemoryStorage(state) {
413
398
  getRollbackTargetCheckpoint: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
414
399
  getRollbackProgressDiff: async param => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
415
400
  getRollbackData: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
416
- writeBatch: async (batch, param, param$1, param$2, param$3, param$4, updatedEntities, param$5, param$6) => handleWriteBatch(state, updatedEntities, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointEventsProcessed),
401
+ writeBatch: async (batch, param, param$1, config, param$2, param$3, updatedEntities, registeredAddresses, param$4, param$5) => handleWriteBatch(state, config, updatedEntities, registeredAddresses, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointEventsProcessed),
417
402
  close: async () => {}
418
403
  };
419
404
  }
@@ -446,36 +431,25 @@ function getRegistrations(config) {
446
431
 
447
432
  function createTestIndexer() {
448
433
  let config = Config.load();
449
- let allEntities = config.allEntities;
434
+ let allEntities = config.userEntities;
450
435
  let entities = {};
451
436
  let entityConfigs = {};
452
437
  allEntities.forEach(entityConfig => {
453
438
  entities[entityConfig.name] = {};
454
439
  entityConfigs[entityConfig.name] = entityConfig;
455
440
  });
456
- let envioAddressesDict = entities[Config.EnvioAddresses.name];
457
- ChainMap.values(config.chainMap).forEach(chainConfig => {
458
- chainConfig.contracts.forEach(contract => {
459
- contract.addresses.forEach(address => {
460
- let entity_id = Config.EnvioAddresses.makeId(chainConfig.id, address);
461
- let entity_chain_id = chainConfig.id;
462
- let entity_contract_name = contract.name;
463
- let entity = {
464
- id: entity_id,
465
- chain_id: entity_chain_id,
466
- registration_block: -1,
467
- registration_log_index: -1,
468
- contract_name: entity_contract_name
469
- };
470
- envioAddressesDict[entity_id] = entity;
471
- });
472
- });
473
- });
441
+ let chainConfigs = ChainMap.values(config.chainMap);
442
+ let contractMapping = config.contractMapping;
443
+ let ecosystem = config.ecosystem.name;
444
+ let addresses = AddressRows.Table.make();
445
+ ChainState.seedConfigAddresses(addresses, chainConfigs, ecosystem, contractMapping);
474
446
  let state = {
475
447
  processInProgress: false,
476
448
  progressBlockByChain: {},
477
449
  entities: entities,
478
450
  entityConfigs: entityConfigs,
451
+ addresses: addresses,
452
+ contractMapping: contractMapping,
479
453
  processChanges: []
480
454
  };
481
455
  let storage = makeInMemoryStorage(state);
@@ -487,16 +461,13 @@ function createTestIndexer() {
487
461
  }
488
462
  let entityOpsDict = {};
489
463
  allEntities.forEach(entityConfig => {
490
- if (entityConfig.name !== Config.EnvioAddresses.name) {
491
- entityOpsDict[entityConfig.name] = {
492
- get: makeEntityGet(state, entityConfig),
493
- getAll: makeEntityGetAll(state, entityConfig),
494
- getWhere: makeEntityGetWhere(state, entityConfig),
495
- getOrThrow: makeEntityGetOrThrow(state, entityConfig),
496
- set: makeEntitySet(state, entityConfig)
497
- };
498
- return;
499
- }
464
+ entityOpsDict[entityConfig.name] = {
465
+ get: makeEntityGet(state, entityConfig),
466
+ getAll: makeEntityGetAll(state, entityConfig),
467
+ getWhere: makeEntityGetWhere(state, entityConfig),
468
+ getOrThrow: makeEntityGetOrThrow(state, entityConfig),
469
+ set: makeEntitySet(state, entityConfig)
470
+ };
500
471
  });
501
472
  let chainIds = [];
502
473
  let chains = Object.create(null);
@@ -534,11 +505,14 @@ function createTestIndexer() {
534
505
  if (state.processInProgress) {
535
506
  Stdlib_JsError.throwWithMessage(`Cannot access ` + contract.name + `.addresses while indexer.process() is running. ` + "Wait for process() to complete before reading contract addresses.");
536
507
  }
537
- return Stdlib_Array.filterMap(Stdlib_Option.getOr(getIndexingAddressesByChain(state)[ChainId.toString(chainConfig.id)], []), ia => {
538
- if (ia.contractName === contract.name) {
539
- return Primitive_option.some(ia.address);
508
+ let contractId = ContractMapping.idOfOrThrow(state.contractMapping, contract.name, undefined);
509
+ return renderRows(AddressRows.Table.rows(state.addresses).filter(row => {
510
+ if (row.chainId === chainConfig.id) {
511
+ return row.contractId === contractId;
512
+ } else {
513
+ return false;
540
514
  }
541
- });
515
+ }), config);
542
516
  }
543
517
  });
544
518
  Object.defineProperty(chainObj, contract.name, {
@@ -608,8 +582,7 @@ function createTestIndexer() {
608
582
  let chainIdStr = param[0];
609
583
  let chains = {};
610
584
  chains[chainIdStr] = processChainConfig;
611
- let indexingAddressesByChain = getIndexingAddressesByChain(state);
612
- let initialState = makeInitialState(config, chains, indexingAddressesByChain);
585
+ let initialState = makeInitialState(config, chains, AddressRows.Table.groupByChain(state.addresses), state.contractMapping);
613
586
  let exitAfterFirstEventBlock = Stdlib_Option.isNone(processChainConfig.endBlock);
614
587
  let resolvedChainDict = {};
615
588
  resolvedChainDict["startBlock"] = processChainConfig.startBlock;
@@ -696,8 +669,8 @@ function createTestIndexer() {
696
669
  }
697
670
 
698
671
  export {
699
- toIndexingAddress,
700
- getIndexingAddressesByChain,
672
+ addressRowsByChain,
673
+ renderRows,
701
674
  rowKey,
702
675
  readChainId,
703
676
  handleLoad,
package/src/Utils.res CHANGED
@@ -199,6 +199,13 @@ module Dict = {
199
199
  }
200
200
  `)
201
201
 
202
+ let clearInPlace: dict<'a> => unit = %raw(`(dict) => {
203
+ for (const key in dict) {
204
+ delete dict[key];
205
+ }
206
+ }
207
+ `)
208
+
202
209
  let unsafeDeleteUndefinedFieldsInPlace: 'a => unit = %raw(`(dict) => {
203
210
  for (var key in dict) {
204
211
  if (dict[key] === undefined) {
package/src/Utils.res.mjs CHANGED
@@ -149,6 +149,12 @@ let deleteInPlace = ((dict, key) => {
149
149
  delete dict[key];
150
150
  });
151
151
 
152
+ let clearInPlace = ((dict) => {
153
+ for (const key in dict) {
154
+ delete dict[key];
155
+ }
156
+ });
157
+
152
158
  let unsafeDeleteUndefinedFieldsInPlace = ((dict) => {
153
159
  for (var key in dict) {
154
160
  if (dict[key] === undefined) {
@@ -175,6 +181,7 @@ let Dict = {
175
181
  size: size,
176
182
  isEmpty: isEmpty,
177
183
  deleteInPlace: deleteInPlace,
184
+ clearInPlace: clearInPlace,
178
185
  unsafeDeleteUndefinedFieldsInPlace: unsafeDeleteUndefinedFieldsInPlace,
179
186
  updateImmutable: updateImmutable,
180
187
  shallowCopy: shallowCopy
@@ -249,7 +256,7 @@ function mergeSorted(f, xs, ys) {
249
256
  return result;
250
257
  }
251
258
 
252
- let clearInPlace = ((arr) => {
259
+ let clearInPlace$1 = ((arr) => {
253
260
  arr.length = 0
254
261
  });
255
262
 
@@ -387,7 +394,7 @@ let $$Array$1 = {
387
394
  unzip: Stdlib_Array.unzip,
388
395
  immutableEmpty: immutableEmpty,
389
396
  mergeSorted: mergeSorted,
390
- clearInPlace: clearInPlace,
397
+ clearInPlace: clearInPlace$1,
391
398
  setIndexImmutable: setIndexImmutable,
392
399
  transposeResults: transposeResults,
393
400
  includes: includes,