envio 3.0.0-alpha.21 → 3.0.0-alpha.22
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.
- package/bin.mjs +2 -48
- package/evm.schema.json +67 -0
- package/fuel.schema.json +67 -0
- package/index.d.ts +822 -38
- package/index.js +5 -3
- package/package.json +10 -8
- package/rescript.json +5 -9
- package/src/Address.res +4 -5
- package/src/Address.res.mjs +9 -12
- package/src/Api.res +15 -0
- package/src/Api.res.mjs +20 -0
- package/src/Batch.res +32 -34
- package/src/Batch.res.mjs +172 -187
- package/src/Bin.res +89 -0
- package/src/Bin.res.mjs +97 -0
- package/src/ChainFetcher.res +33 -57
- package/src/ChainFetcher.res.mjs +197 -227
- package/src/ChainManager.res +6 -14
- package/src/ChainManager.res.mjs +74 -85
- package/src/ChainMap.res +14 -16
- package/src/ChainMap.res.mjs +38 -38
- package/src/Config.res +193 -135
- package/src/Config.res.mjs +566 -592
- package/src/Core.res +182 -0
- package/src/Core.res.mjs +207 -0
- package/src/Ecosystem.res +25 -4
- package/src/Ecosystem.res.mjs +12 -13
- package/src/Env.res +20 -13
- package/src/Env.res.mjs +124 -113
- package/src/EnvSafe.res +269 -0
- package/src/EnvSafe.res.mjs +296 -0
- package/src/EnvSafe.resi +18 -0
- package/src/Envio.res +37 -26
- package/src/Envio.res.mjs +59 -60
- package/src/ErrorHandling.res +2 -2
- package/src/ErrorHandling.res.mjs +15 -15
- package/src/EventConfigBuilder.res +219 -81
- package/src/EventConfigBuilder.res.mjs +259 -202
- package/src/EventProcessing.res +27 -38
- package/src/EventProcessing.res.mjs +165 -183
- package/src/EventUtils.res +11 -11
- package/src/EventUtils.res.mjs +21 -22
- package/src/EvmTypes.res +0 -1
- package/src/EvmTypes.res.mjs +5 -5
- package/src/FetchState.res +360 -256
- package/src/FetchState.res.mjs +958 -914
- package/src/GlobalState.res +365 -351
- package/src/GlobalState.res.mjs +958 -992
- package/src/GlobalStateManager.res +1 -2
- package/src/GlobalStateManager.res.mjs +36 -44
- package/src/HandlerLoader.res +107 -23
- package/src/HandlerLoader.res.mjs +128 -38
- package/src/HandlerRegister.res +127 -103
- package/src/HandlerRegister.res.mjs +164 -164
- package/src/HandlerRegister.resi +12 -4
- package/src/Hasura.res +35 -22
- package/src/Hasura.res.mjs +158 -167
- package/src/InMemoryStore.res +20 -27
- package/src/InMemoryStore.res.mjs +64 -80
- package/src/InMemoryTable.res +34 -39
- package/src/InMemoryTable.res.mjs +165 -170
- package/src/Internal.res +52 -33
- package/src/Internal.res.mjs +84 -81
- package/src/LazyLoader.res.mjs +55 -61
- package/src/LoadLayer.res +77 -78
- package/src/LoadLayer.res.mjs +160 -189
- package/src/LoadManager.res +16 -21
- package/src/LoadManager.res.mjs +79 -84
- package/src/LogSelection.res +236 -68
- package/src/LogSelection.res.mjs +211 -141
- package/src/Logging.res +13 -9
- package/src/Logging.res.mjs +130 -143
- package/src/Main.res +428 -51
- package/src/Main.res.mjs +528 -271
- package/src/Persistence.res +77 -84
- package/src/Persistence.res.mjs +131 -132
- package/src/PgStorage.res +291 -167
- package/src/PgStorage.res.mjs +797 -817
- package/src/Prometheus.res +50 -58
- package/src/Prometheus.res.mjs +345 -373
- package/src/ReorgDetection.res +22 -24
- package/src/ReorgDetection.res.mjs +100 -106
- package/src/SafeCheckpointTracking.res +7 -7
- package/src/SafeCheckpointTracking.res.mjs +40 -43
- package/src/SimulateItems.res +41 -49
- package/src/SimulateItems.res.mjs +257 -272
- package/src/Sink.res +2 -2
- package/src/Sink.res.mjs +22 -26
- package/src/TableIndices.res +1 -2
- package/src/TableIndices.res.mjs +42 -48
- package/src/TestIndexer.res +196 -189
- package/src/TestIndexer.res.mjs +536 -536
- package/src/TestIndexerProxyStorage.res +15 -16
- package/src/TestIndexerProxyStorage.res.mjs +98 -122
- package/src/TestIndexerWorker.res +4 -0
- package/src/TestIndexerWorker.res.mjs +7 -0
- package/src/Throttler.res +3 -3
- package/src/Throttler.res.mjs +23 -24
- package/src/Time.res +1 -1
- package/src/Time.res.mjs +18 -21
- package/src/TopicFilter.res +3 -3
- package/src/TopicFilter.res.mjs +29 -30
- package/src/UserContext.res +93 -54
- package/src/UserContext.res.mjs +197 -182
- package/src/Utils.res +141 -86
- package/src/Utils.res.mjs +334 -295
- package/src/bindings/BigDecimal.res +0 -2
- package/src/bindings/BigDecimal.res.mjs +19 -23
- package/src/bindings/ClickHouse.res +28 -27
- package/src/bindings/ClickHouse.res.mjs +243 -240
- package/src/bindings/DateFns.res +11 -11
- package/src/bindings/DateFns.res.mjs +7 -7
- package/src/bindings/EventSource.res.mjs +2 -2
- package/src/bindings/Express.res +2 -5
- package/src/bindings/Hrtime.res +2 -2
- package/src/bindings/Hrtime.res.mjs +30 -32
- package/src/bindings/Lodash.res.mjs +1 -1
- package/src/bindings/NodeJs.res +14 -9
- package/src/bindings/NodeJs.res.mjs +20 -20
- package/src/bindings/Pino.res +8 -10
- package/src/bindings/Pino.res.mjs +40 -43
- package/src/bindings/Postgres.res +2 -5
- package/src/bindings/Postgres.res.mjs +9 -9
- package/src/bindings/PromClient.res +17 -2
- package/src/bindings/PromClient.res.mjs +30 -7
- package/src/bindings/SDSL.res.mjs +2 -2
- package/src/bindings/Viem.res +4 -4
- package/src/bindings/Viem.res.mjs +20 -22
- package/src/bindings/Vitest.res +1 -1
- package/src/bindings/Vitest.res.mjs +2 -2
- package/src/bindings/WebSocket.res +1 -1
- package/src/db/EntityHistory.res +9 -3
- package/src/db/EntityHistory.res.mjs +84 -59
- package/src/db/InternalTable.res +62 -60
- package/src/db/InternalTable.res.mjs +271 -203
- package/src/db/Schema.res +1 -2
- package/src/db/Schema.res.mjs +28 -32
- package/src/db/Table.res +28 -27
- package/src/db/Table.res.mjs +276 -292
- package/src/sources/EventRouter.res +21 -16
- package/src/sources/EventRouter.res.mjs +55 -57
- package/src/sources/Evm.res +17 -1
- package/src/sources/Evm.res.mjs +16 -8
- package/src/sources/EvmChain.res +15 -17
- package/src/sources/EvmChain.res.mjs +40 -42
- package/src/sources/Fuel.res +14 -1
- package/src/sources/Fuel.res.mjs +16 -8
- package/src/sources/FuelSDK.res +1 -1
- package/src/sources/FuelSDK.res.mjs +6 -8
- package/src/sources/HyperFuel.res +8 -10
- package/src/sources/HyperFuel.res.mjs +113 -123
- package/src/sources/HyperFuelClient.res.mjs +6 -7
- package/src/sources/HyperFuelSource.res +19 -20
- package/src/sources/HyperFuelSource.res.mjs +339 -356
- package/src/sources/HyperSync.res +11 -13
- package/src/sources/HyperSync.res.mjs +206 -220
- package/src/sources/HyperSyncClient.res +5 -7
- package/src/sources/HyperSyncClient.res.mjs +70 -75
- package/src/sources/HyperSyncHeightStream.res +8 -9
- package/src/sources/HyperSyncHeightStream.res.mjs +78 -86
- package/src/sources/HyperSyncJsonApi.res +18 -15
- package/src/sources/HyperSyncJsonApi.res.mjs +201 -231
- package/src/sources/HyperSyncSource.res +17 -21
- package/src/sources/HyperSyncSource.res.mjs +268 -290
- package/src/sources/Rpc.res +5 -5
- package/src/sources/Rpc.res.mjs +168 -192
- package/src/sources/RpcSource.res +166 -167
- package/src/sources/RpcSource.res.mjs +972 -1046
- package/src/sources/RpcWebSocketHeightStream.res +10 -11
- package/src/sources/RpcWebSocketHeightStream.res.mjs +131 -145
- package/src/sources/SimulateSource.res +1 -1
- package/src/sources/SimulateSource.res.mjs +35 -38
- package/src/sources/Source.res +1 -1
- package/src/sources/Source.res.mjs +3 -3
- package/src/sources/SourceManager.res +39 -20
- package/src/sources/SourceManager.res.mjs +340 -371
- package/src/sources/SourceManager.resi +2 -1
- package/src/sources/Svm.res +12 -5
- package/src/sources/Svm.res.mjs +44 -41
- package/src/tui/Tui.res +23 -12
- package/src/tui/Tui.res.mjs +292 -290
- package/src/tui/bindings/Ink.res +2 -4
- package/src/tui/bindings/Ink.res.mjs +35 -41
- package/src/tui/components/BufferedProgressBar.res +7 -7
- package/src/tui/components/BufferedProgressBar.res.mjs +46 -46
- package/src/tui/components/CustomHooks.res +1 -2
- package/src/tui/components/CustomHooks.res.mjs +102 -122
- package/src/tui/components/Messages.res +1 -2
- package/src/tui/components/Messages.res.mjs +38 -42
- package/src/tui/components/SyncETA.res +10 -11
- package/src/tui/components/SyncETA.res.mjs +178 -196
- package/src/tui/components/TuiData.res +1 -1
- package/src/tui/components/TuiData.res.mjs +7 -6
- package/src/vendored/Rest.res +52 -66
- package/src/vendored/Rest.res.mjs +324 -364
- package/svm.schema.json +67 -0
- package/src/Address.gen.ts +0 -8
- package/src/Config.gen.ts +0 -19
- package/src/Envio.gen.ts +0 -55
- package/src/EvmTypes.gen.ts +0 -6
- package/src/InMemoryStore.gen.ts +0 -6
- package/src/Internal.gen.ts +0 -64
- package/src/PgStorage.gen.ts +0 -10
- package/src/PgStorage.res.d.mts +0 -5
- package/src/Types.ts +0 -56
- package/src/bindings/BigDecimal.gen.ts +0 -14
- package/src/bindings/BigDecimal.res.d.mts +0 -5
- package/src/bindings/BigInt.gen.ts +0 -10
- package/src/bindings/BigInt.res +0 -70
- package/src/bindings/BigInt.res.d.mts +0 -5
- package/src/bindings/BigInt.res.mjs +0 -154
- package/src/bindings/Ethers.res.d.mts +0 -5
- package/src/bindings/Pino.gen.ts +0 -17
- package/src/bindings/Postgres.gen.ts +0 -8
- package/src/bindings/Postgres.res.d.mts +0 -5
- package/src/bindings/Promise.res +0 -67
- package/src/bindings/Promise.res.mjs +0 -26
- package/src/db/InternalTable.gen.ts +0 -36
- package/src/sources/HyperSyncClient.gen.ts +0 -19
package/src/TestIndexer.res
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
open Belt
|
|
2
|
-
|
|
3
1
|
type evmChainConfig = {
|
|
4
2
|
startBlock?: int,
|
|
5
3
|
endBlock?: int,
|
|
@@ -36,30 +34,25 @@ type testIndexerState = {
|
|
|
36
34
|
mutable processChanges: array<unknown>,
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
// Cast Internal.entity back to
|
|
40
|
-
external
|
|
41
|
-
"%identity"
|
|
37
|
+
// Cast Internal.entity back to EnvioAddresses.t
|
|
38
|
+
external castToEnvioAddresses: Internal.entity => InternalTable.EnvioAddresses.t = "%identity"
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
dc: InternalTable.DynamicContractRegistry.t,
|
|
46
|
-
): Internal.indexingContract => {
|
|
47
|
-
address: dc.contractAddress,
|
|
40
|
+
let toIndexingAddress = (dc: InternalTable.EnvioAddresses.t): Internal.indexingAddress => {
|
|
41
|
+
address: dc->Config.EnvioAddresses.getAddress,
|
|
48
42
|
contractName: dc.contractName,
|
|
49
|
-
|
|
50
|
-
registrationBlock: Some(dc.registeringEventBlockNumber),
|
|
43
|
+
registrationBlock: dc.registrationBlock,
|
|
51
44
|
}
|
|
52
45
|
|
|
53
46
|
let handleLoadByIds = (
|
|
54
47
|
state: testIndexerState,
|
|
55
48
|
~tableName: string,
|
|
56
49
|
~ids: array<string>,
|
|
57
|
-
):
|
|
58
|
-
let entityDict = state.entities->
|
|
59
|
-
let entityConfig = state.entityConfigs->
|
|
50
|
+
): JSON.t => {
|
|
51
|
+
let entityDict = state.entities->Dict.get(tableName)->Option.getOr(Dict.make())
|
|
52
|
+
let entityConfig = state.entityConfigs->Dict.getUnsafe(tableName)
|
|
60
53
|
let results = []
|
|
61
54
|
ids->Array.forEach(id => {
|
|
62
|
-
switch entityDict->
|
|
55
|
+
switch entityDict->Dict.get(id) {
|
|
63
56
|
| Some(entity) =>
|
|
64
57
|
// Serialize entity back to JSON for worker thread
|
|
65
58
|
let jsonEntity = entity->S.reverseConvertToJsonOrThrow(entityConfig.schema)
|
|
@@ -67,24 +60,24 @@ let handleLoadByIds = (
|
|
|
67
60
|
| None => ()
|
|
68
61
|
}
|
|
69
62
|
})
|
|
70
|
-
results->
|
|
63
|
+
results->JSON.Encode.array
|
|
71
64
|
}
|
|
72
65
|
|
|
73
66
|
let handleLoadByField = (
|
|
74
67
|
state: testIndexerState,
|
|
75
68
|
~tableName: string,
|
|
76
69
|
~fieldName: string,
|
|
77
|
-
~fieldValue:
|
|
70
|
+
~fieldValue: JSON.t,
|
|
78
71
|
~operator: Persistence.operator,
|
|
79
|
-
):
|
|
80
|
-
let entityDict = state.entities->
|
|
81
|
-
let entityConfig = state.entityConfigs->
|
|
72
|
+
): JSON.t => {
|
|
73
|
+
let entityDict = state.entities->Dict.get(tableName)->Option.getOr(Dict.make())
|
|
74
|
+
let entityConfig = state.entityConfigs->Dict.getUnsafe(tableName)
|
|
82
75
|
let results = []
|
|
83
76
|
|
|
84
77
|
// Get the field schema from the entity's table to properly parse the JSON field value
|
|
85
78
|
let fieldSchema = switch entityConfig.table->Table.getFieldByName(fieldName) {
|
|
86
79
|
| Some(Table.Field({fieldSchema})) => fieldSchema
|
|
87
|
-
| _ =>
|
|
80
|
+
| _ => JsError.throwWithMessage(`Field ${fieldName} not found in entity ${tableName}`)
|
|
88
81
|
}
|
|
89
82
|
|
|
90
83
|
// Parse JSON field value to typed value using the field's schema
|
|
@@ -93,11 +86,11 @@ let handleLoadByField = (
|
|
|
93
86
|
// Compare using TableIndices.FieldValue logic (same approach as InMemoryTable)
|
|
94
87
|
// This properly handles bigint and BigDecimal comparisons
|
|
95
88
|
entityDict
|
|
96
|
-
->
|
|
89
|
+
->Dict.valuesToArray
|
|
97
90
|
->Array.forEach(entity => {
|
|
98
91
|
// Cast entity to dict of field values (same approach as InMemoryTable)
|
|
99
92
|
let entityAsDict = entity->(Utils.magic: Internal.entity => dict<TableIndices.FieldValue.t>)
|
|
100
|
-
switch entityAsDict->
|
|
93
|
+
switch entityAsDict->Dict.get(fieldName) {
|
|
101
94
|
| Some(entityFieldValue) => {
|
|
102
95
|
let matches = switch operator {
|
|
103
96
|
| #"=" => entityFieldValue->TableIndices.FieldValue.eq(parsedFieldValue)
|
|
@@ -114,7 +107,7 @@ let handleLoadByField = (
|
|
|
114
107
|
}
|
|
115
108
|
})
|
|
116
109
|
|
|
117
|
-
results->
|
|
110
|
+
results->JSON.Encode.array
|
|
118
111
|
}
|
|
119
112
|
|
|
120
113
|
let handleWriteBatch = (
|
|
@@ -127,17 +120,17 @@ let handleWriteBatch = (
|
|
|
127
120
|
): unit => {
|
|
128
121
|
// Group entity changes by checkpointId
|
|
129
122
|
// checkpointId -> entityName -> entityChange
|
|
130
|
-
let changesByCheckpoint: dict<dict<entityChange>> =
|
|
123
|
+
let changesByCheckpoint: dict<dict<entityChange>> = Dict.make()
|
|
131
124
|
|
|
132
125
|
updatedEntities->Array.forEach(({entityName, updates}) => {
|
|
133
|
-
let entityDict = switch state.entities->
|
|
126
|
+
let entityDict = switch state.entities->Dict.get(entityName) {
|
|
134
127
|
| Some(dict) => dict
|
|
135
128
|
| None =>
|
|
136
|
-
let dict =
|
|
137
|
-
state.entities->
|
|
129
|
+
let dict = Dict.make()
|
|
130
|
+
state.entities->Dict.set(entityName, dict)
|
|
138
131
|
dict
|
|
139
132
|
}
|
|
140
|
-
let entityConfig = state.entityConfigs->
|
|
133
|
+
let entityConfig = state.entityConfigs->Dict.getUnsafe(entityName)
|
|
141
134
|
|
|
142
135
|
updates->Array.forEach(update => {
|
|
143
136
|
// Helper to process a single change (Set or Delete)
|
|
@@ -149,44 +142,44 @@ let handleWriteBatch = (
|
|
|
149
142
|
let parsedEntity = entity->S.parseOrThrow(entityConfig.schema)
|
|
150
143
|
|
|
151
144
|
// Update entities dict with parsed entity for load operations
|
|
152
|
-
entityDict->
|
|
145
|
+
entityDict->Dict.set(entityId, parsedEntity)
|
|
153
146
|
|
|
154
147
|
// Track change by checkpoint
|
|
155
148
|
let checkpointKey = checkpointId->BigInt.toString
|
|
156
|
-
let entityChanges = switch changesByCheckpoint->
|
|
149
|
+
let entityChanges = switch changesByCheckpoint->Dict.get(checkpointKey) {
|
|
157
150
|
| Some(changes) => changes
|
|
158
151
|
| None =>
|
|
159
|
-
let changes =
|
|
160
|
-
changesByCheckpoint->
|
|
152
|
+
let changes = Dict.make()
|
|
153
|
+
changesByCheckpoint->Dict.set(checkpointKey, changes)
|
|
161
154
|
changes
|
|
162
155
|
}
|
|
163
|
-
let entityChange = switch entityChanges->
|
|
156
|
+
let entityChange = switch entityChanges->Dict.get(entityName) {
|
|
164
157
|
| Some(change) => change
|
|
165
158
|
| None =>
|
|
166
159
|
let change = {sets: [], deleted: []}
|
|
167
|
-
entityChanges->
|
|
160
|
+
entityChanges->Dict.set(entityName, change)
|
|
168
161
|
change
|
|
169
162
|
}
|
|
170
163
|
entityChange.sets->Array.push(parsedEntity->Utils.magic)->ignore
|
|
171
164
|
|
|
172
165
|
| Delete({entityId, checkpointId}) =>
|
|
173
166
|
// Update entities dict for load operations
|
|
174
|
-
|
|
167
|
+
Dict.delete(entityDict->Obj.magic, entityId)
|
|
175
168
|
|
|
176
169
|
// Track change by checkpoint
|
|
177
170
|
let checkpointKey = checkpointId->BigInt.toString
|
|
178
|
-
let entityChanges = switch changesByCheckpoint->
|
|
171
|
+
let entityChanges = switch changesByCheckpoint->Dict.get(checkpointKey) {
|
|
179
172
|
| Some(changes) => changes
|
|
180
173
|
| None =>
|
|
181
|
-
let changes =
|
|
182
|
-
changesByCheckpoint->
|
|
174
|
+
let changes = Dict.make()
|
|
175
|
+
changesByCheckpoint->Dict.set(checkpointKey, changes)
|
|
183
176
|
changes
|
|
184
177
|
}
|
|
185
|
-
let entityChange = switch entityChanges->
|
|
178
|
+
let entityChange = switch entityChanges->Dict.get(entityName) {
|
|
186
179
|
| Some(change) => change
|
|
187
180
|
| None =>
|
|
188
181
|
let change = {sets: [], deleted: []}
|
|
189
|
-
entityChanges->
|
|
182
|
+
entityChanges->Dict.set(entityName, change)
|
|
190
183
|
change
|
|
191
184
|
}
|
|
192
185
|
entityChange.deleted->Array.push(entityId)->ignore
|
|
@@ -206,96 +199,97 @@ let handleWriteBatch = (
|
|
|
206
199
|
// Build combined checkpoint + entity changes objects
|
|
207
200
|
for i in 0 to checkpointIds->Array.length - 1 {
|
|
208
201
|
let checkpointId = checkpointIds->Array.getUnsafe(i)
|
|
209
|
-
let change: dict<unknown> =
|
|
202
|
+
let change: dict<unknown> = Dict.make()
|
|
210
203
|
|
|
211
204
|
// Update progress tracking from checkpoint data
|
|
212
|
-
state.progressBlockByChain->
|
|
205
|
+
state.progressBlockByChain->Dict.set(
|
|
213
206
|
checkpointChainIds->Array.getUnsafe(i)->Int.toString,
|
|
214
207
|
checkpointBlockNumbers->Array.getUnsafe(i),
|
|
215
208
|
)
|
|
216
209
|
|
|
217
210
|
// Add checkpoint metadata
|
|
218
|
-
change->
|
|
219
|
-
change->
|
|
220
|
-
change->
|
|
221
|
-
"eventsProcessed",
|
|
222
|
-
checkpointEventsProcessed->Array.getUnsafe(i)->Utils.magic,
|
|
223
|
-
)
|
|
211
|
+
change->Dict.set("block", checkpointBlockNumbers->Array.getUnsafe(i)->Utils.magic)
|
|
212
|
+
change->Dict.set("chainId", checkpointChainIds->Array.getUnsafe(i)->Utils.magic)
|
|
213
|
+
change->Dict.set("eventsProcessed", checkpointEventsProcessed->Array.getUnsafe(i)->Utils.magic)
|
|
224
214
|
|
|
225
215
|
// Add entity changes for this checkpoint
|
|
226
216
|
let checkpointKey = checkpointId->BigInt.toString
|
|
227
|
-
switch changesByCheckpoint->
|
|
217
|
+
switch changesByCheckpoint->Dict.get(checkpointKey) {
|
|
228
218
|
| Some(entityChanges) =>
|
|
229
219
|
entityChanges
|
|
230
|
-
->
|
|
220
|
+
->Dict.toArray
|
|
231
221
|
->Array.forEach(((entityName, {sets, deleted})) => {
|
|
232
|
-
// Transform
|
|
233
|
-
if entityName === InternalTable.
|
|
234
|
-
let entityObj: dict<unknown> =
|
|
222
|
+
// Transform envio_addresses to addresses with simplified structure
|
|
223
|
+
if entityName === InternalTable.EnvioAddresses.name {
|
|
224
|
+
let entityObj: dict<unknown> = Dict.make()
|
|
235
225
|
if sets->Array.length > 0 {
|
|
236
226
|
// Transform sets to simplified {address, contract} objects
|
|
237
227
|
let simplifiedSets = sets->Array.map(entity => {
|
|
238
|
-
let dc = entity->Utils.magic->
|
|
239
|
-
{"address": dc.
|
|
228
|
+
let dc = entity->Utils.magic->castToEnvioAddresses
|
|
229
|
+
{"address": dc->Config.EnvioAddresses.getAddress, "contract": dc.contractName}
|
|
240
230
|
})
|
|
241
|
-
entityObj->
|
|
231
|
+
entityObj->Dict.set(
|
|
232
|
+
"sets",
|
|
233
|
+
simplifiedSets->(
|
|
234
|
+
Utils.magic: array<{"address": Address.t, "contract": string}> => unknown
|
|
235
|
+
),
|
|
236
|
+
)
|
|
242
237
|
}
|
|
243
238
|
// Note: deleted is not relevant for addresses since we use address string directly
|
|
244
|
-
change->
|
|
239
|
+
change->Dict.set("addresses", entityObj->(Utils.magic: dict<unknown> => unknown))
|
|
245
240
|
} else {
|
|
246
|
-
let entityObj: dict<unknown> =
|
|
241
|
+
let entityObj: dict<unknown> = Dict.make()
|
|
247
242
|
if sets->Array.length > 0 {
|
|
248
|
-
entityObj->
|
|
243
|
+
entityObj->Dict.set("sets", sets->(Utils.magic: array<unknown> => unknown))
|
|
249
244
|
}
|
|
250
245
|
if deleted->Array.length > 0 {
|
|
251
|
-
entityObj->
|
|
246
|
+
entityObj->Dict.set("deleted", deleted->(Utils.magic: array<string> => unknown))
|
|
252
247
|
}
|
|
253
|
-
change->
|
|
248
|
+
change->Dict.set(entityName, entityObj->(Utils.magic: dict<unknown> => unknown))
|
|
254
249
|
}
|
|
255
250
|
})
|
|
256
251
|
| None => ()
|
|
257
252
|
}
|
|
258
253
|
|
|
259
|
-
state.processChanges
|
|
254
|
+
state.processChanges
|
|
255
|
+
->Array.push(change->(Utils.magic: dict<unknown> => unknown))
|
|
256
|
+
->ignore
|
|
260
257
|
}
|
|
261
258
|
}
|
|
262
259
|
|
|
263
260
|
let makeInitialState = (
|
|
264
261
|
~config: Config.t,
|
|
265
|
-
~processConfigChains:
|
|
266
|
-
~
|
|
262
|
+
~processConfigChains: dict<chainConfig>,
|
|
263
|
+
~indexingAddressesByChain: dict<array<Internal.indexingAddress>>,
|
|
267
264
|
): Persistence.initialState => {
|
|
268
|
-
let chainKeys = processConfigChains->
|
|
265
|
+
let chainKeys = processConfigChains->Dict.keysToArray
|
|
269
266
|
let chains = chainKeys->Array.map(chainIdStr => {
|
|
270
|
-
let chainId = chainIdStr->Int.fromString->Option.
|
|
267
|
+
let chainId = chainIdStr->Int.fromString->Option.getOr(0)
|
|
271
268
|
let chain = ChainMap.Chain.makeUnsafe(~chainId)
|
|
272
269
|
|
|
273
270
|
if !(config.chainMap->ChainMap.has(chain)) {
|
|
274
|
-
|
|
271
|
+
JsError.throwWithMessage(`Chain ${chainIdStr} is not configured in config.yaml`)
|
|
275
272
|
}
|
|
276
273
|
|
|
277
|
-
let processChainConfig = processConfigChains->
|
|
278
|
-
let
|
|
279
|
-
dynamicContractsByChain
|
|
280
|
-
->Js.Dict.get(chainIdStr)
|
|
281
|
-
->Option.getWithDefault([])
|
|
274
|
+
let processChainConfig = processConfigChains->Dict.getUnsafe(chainIdStr)
|
|
275
|
+
let indexingAddresses = indexingAddressesByChain->Dict.get(chainIdStr)->Option.getOr([])
|
|
282
276
|
{
|
|
283
277
|
Persistence.id: chainId,
|
|
284
278
|
startBlock: processChainConfig.startBlock,
|
|
285
279
|
endBlock: processChainConfig.endBlock,
|
|
286
|
-
sourceBlockNumber: processChainConfig.endBlock->Option.
|
|
280
|
+
sourceBlockNumber: processChainConfig.endBlock->Option.getOr(0),
|
|
287
281
|
maxReorgDepth: 0, // No reorg support in test indexer
|
|
288
282
|
progressBlockNumber: -1,
|
|
289
283
|
numEventsProcessed: 0.,
|
|
290
284
|
firstEventBlockNumber: None,
|
|
291
285
|
timestampCaughtUpToHeadOrEndblock: None,
|
|
292
|
-
|
|
286
|
+
indexingAddresses,
|
|
293
287
|
}
|
|
294
288
|
})
|
|
295
289
|
|
|
296
290
|
{
|
|
297
291
|
cleanRun: true,
|
|
298
|
-
cache:
|
|
292
|
+
cache: Dict.make(),
|
|
299
293
|
chains,
|
|
300
294
|
checkpointId: InternalTable.Checkpoints.initialCheckpointId,
|
|
301
295
|
reorgCheckpoints: [],
|
|
@@ -305,7 +299,7 @@ let makeInitialState = (
|
|
|
305
299
|
type rawChainConfig = {
|
|
306
300
|
startBlock: option<int>,
|
|
307
301
|
endBlock: option<int>,
|
|
308
|
-
simulate: option<array<
|
|
302
|
+
simulate: option<array<JSON.t>>,
|
|
309
303
|
}
|
|
310
304
|
|
|
311
305
|
let rawChainConfigSchema = S.schema(s => {
|
|
@@ -321,25 +315,23 @@ let processConfigSchema = S.schema(s =>
|
|
|
321
315
|
)
|
|
322
316
|
|
|
323
317
|
let getSimulateEndBlock = (
|
|
324
|
-
~simulateItems: array<
|
|
318
|
+
~simulateItems: array<JSON.t>,
|
|
325
319
|
~config: Config.t,
|
|
326
320
|
~startBlock: int,
|
|
327
321
|
): int => {
|
|
328
322
|
let maxBlock = ref(startBlock)
|
|
329
323
|
simulateItems->Array.forEach(rawJson => {
|
|
330
|
-
let blockJson: option<
|
|
331
|
-
(rawJson->(Utils.magic:
|
|
332
|
-
->(Utils.magic: 'a =>
|
|
333
|
-
->
|
|
324
|
+
let blockJson: option<JSON.t> =
|
|
325
|
+
(rawJson->(Utils.magic: JSON.t => {..}))["block"]
|
|
326
|
+
->(Utils.magic: 'a => Nullable.t<JSON.t>)
|
|
327
|
+
->Nullable.toOption
|
|
334
328
|
switch blockJson {
|
|
335
329
|
| Some(bj) =>
|
|
336
|
-
let blockDict = bj->(Utils.magic:
|
|
330
|
+
let blockDict = bj->(Utils.magic: JSON.t => dict<JSON.t>)
|
|
337
331
|
let n: option<int> =
|
|
338
332
|
blockDict
|
|
339
|
-
->
|
|
340
|
-
->Option.flatMap(v =>
|
|
341
|
-
v->(Utils.magic: Js.Json.t => Js.Nullable.t<int>)->Js.Nullable.toOption
|
|
342
|
-
)
|
|
333
|
+
->Dict.get(config.ecosystem.blockNumberName)
|
|
334
|
+
->Option.flatMap(v => v->(Utils.magic: JSON.t => Nullable.t<int>)->Nullable.toOption)
|
|
343
335
|
switch n {
|
|
344
336
|
| Some(v) if v > maxBlock.contents => maxBlock := v
|
|
345
337
|
| _ => ()
|
|
@@ -360,11 +352,12 @@ let parseBlockRange = (
|
|
|
360
352
|
): chainConfig => {
|
|
361
353
|
let chainId = switch chainIdStr->Int.fromString {
|
|
362
354
|
| Some(id) => id
|
|
363
|
-
| None =>
|
|
355
|
+
| None =>
|
|
356
|
+
JsError.throwWithMessage(`Invalid chain ID "${chainIdStr}": expected a numeric chain ID`)
|
|
364
357
|
}
|
|
365
358
|
let chain = ChainMap.Chain.makeUnsafe(~chainId)
|
|
366
359
|
if !(config.chainMap->ChainMap.has(chain)) {
|
|
367
|
-
|
|
360
|
+
JsError.throwWithMessage(`Chain ${chainIdStr} is not configured in config.yaml`)
|
|
368
361
|
}
|
|
369
362
|
let configChain = config.chainMap->ChainMap.get(chain)
|
|
370
363
|
|
|
@@ -382,7 +375,7 @@ let parseBlockRange = (
|
|
|
382
375
|
| None if rawChainConfig.simulate->Option.isSome =>
|
|
383
376
|
Some(
|
|
384
377
|
getSimulateEndBlock(
|
|
385
|
-
~simulateItems=rawChainConfig.simulate->Option.
|
|
378
|
+
~simulateItems=rawChainConfig.simulate->Option.getOrThrow,
|
|
386
379
|
~config,
|
|
387
380
|
~startBlock,
|
|
388
381
|
),
|
|
@@ -391,7 +384,7 @@ let parseBlockRange = (
|
|
|
391
384
|
}
|
|
392
385
|
|
|
393
386
|
if startBlock < configChain.startBlock {
|
|
394
|
-
|
|
387
|
+
JsError.throwWithMessage(
|
|
395
388
|
`Invalid block range for chain ${chainIdStr}: startBlock (${startBlock->Int.toString}) is less than config.startBlock (${configChain.startBlock->Int.toString}). ` ++
|
|
396
389
|
`Either use startBlock >= ${configChain.startBlock->Int.toString} or create a new test indexer with createTestIndexer().`,
|
|
397
390
|
)
|
|
@@ -399,7 +392,7 @@ let parseBlockRange = (
|
|
|
399
392
|
|
|
400
393
|
switch (endBlock, configChain.endBlock) {
|
|
401
394
|
| (Some(eb), Some(configEndBlock)) if eb > configEndBlock =>
|
|
402
|
-
|
|
395
|
+
JsError.throwWithMessage(
|
|
403
396
|
`Invalid block range for chain ${chainIdStr}: endBlock (${eb->Int.toString}) exceeds config.endBlock (${configEndBlock->Int.toString}). ` ++
|
|
404
397
|
`Either use endBlock <= ${configEndBlock->Int.toString} or create a new test indexer with createTestIndexer().`,
|
|
405
398
|
)
|
|
@@ -408,7 +401,7 @@ let parseBlockRange = (
|
|
|
408
401
|
|
|
409
402
|
switch progressBlock {
|
|
410
403
|
| Some(prevEndBlock) if startBlock <= prevEndBlock =>
|
|
411
|
-
|
|
404
|
+
JsError.throwWithMessage(
|
|
412
405
|
`Invalid block range for chain ${chainIdStr}: startBlock (${startBlock->Int.toString}) must be greater than previously processed endBlock (${prevEndBlock->Int.toString}). ` ++
|
|
413
406
|
`Either use startBlock > ${prevEndBlock->Int.toString} or create a new test indexer with createTestIndexer().`,
|
|
414
407
|
)
|
|
@@ -426,13 +419,12 @@ let getEntityFromState = (
|
|
|
426
419
|
~methodName: string,
|
|
427
420
|
): option<Internal.entity> => {
|
|
428
421
|
if state.processInProgress {
|
|
429
|
-
|
|
422
|
+
JsError.throwWithMessage(
|
|
430
423
|
`Cannot call ${entityConfig.name}.${methodName}() while indexer.process() is running. ` ++ "Wait for process() to complete before accessing entities directly.",
|
|
431
424
|
)
|
|
432
425
|
}
|
|
433
|
-
let entityDict =
|
|
434
|
-
|
|
435
|
-
entityDict->Js.Dict.get(entityId)
|
|
426
|
+
let entityDict = state.entities->Dict.get(entityConfig.name)->Option.getOr(Dict.make())
|
|
427
|
+
entityDict->Dict.get(entityId)
|
|
436
428
|
}
|
|
437
429
|
|
|
438
430
|
let makeEntityGet = (~state: testIndexerState, ~entityConfig: Internal.entityConfig): (
|
|
@@ -454,7 +446,7 @@ let makeEntityGetOrThrow = (~state: testIndexerState, ~entityConfig: Internal.en
|
|
|
454
446
|
| Some(m) => m
|
|
455
447
|
| None => `Entity ${entityConfig.name} with id ${entityId} not found`
|
|
456
448
|
}
|
|
457
|
-
|
|
449
|
+
JsError.throwWithMessage(msg)
|
|
458
450
|
}
|
|
459
451
|
}
|
|
460
452
|
}
|
|
@@ -464,18 +456,18 @@ let makeEntitySet = (~state: testIndexerState, ~entityConfig: Internal.entityCon
|
|
|
464
456
|
) => {
|
|
465
457
|
entity => {
|
|
466
458
|
if state.processInProgress {
|
|
467
|
-
|
|
459
|
+
JsError.throwWithMessage(
|
|
468
460
|
`Cannot call ${entityConfig.name}.set() while indexer.process() is running. ` ++ "Wait for process() to complete before modifying entities directly.",
|
|
469
461
|
)
|
|
470
462
|
}
|
|
471
|
-
let entityDict = switch state.entities->
|
|
463
|
+
let entityDict = switch state.entities->Dict.get(entityConfig.name) {
|
|
472
464
|
| Some(dict) => dict
|
|
473
465
|
| None =>
|
|
474
|
-
let dict =
|
|
475
|
-
state.entities->
|
|
466
|
+
let dict = Dict.make()
|
|
467
|
+
state.entities->Dict.set(entityConfig.name, dict)
|
|
476
468
|
dict
|
|
477
469
|
}
|
|
478
|
-
entityDict->
|
|
470
|
+
entityDict->Dict.set(entity.id, entity)
|
|
479
471
|
}
|
|
480
472
|
}
|
|
481
473
|
|
|
@@ -484,13 +476,12 @@ let makeEntityGetAll = (~state: testIndexerState, ~entityConfig: Internal.entity
|
|
|
484
476
|
) => {
|
|
485
477
|
() => {
|
|
486
478
|
if state.processInProgress {
|
|
487
|
-
|
|
479
|
+
JsError.throwWithMessage(
|
|
488
480
|
`Cannot call ${entityConfig.name}.getAll() while indexer.process() is running. ` ++ "Wait for process() to complete before accessing entities directly.",
|
|
489
481
|
)
|
|
490
482
|
}
|
|
491
|
-
let entityDict =
|
|
492
|
-
|
|
493
|
-
Promise.resolve(entityDict->Js.Dict.values)
|
|
483
|
+
let entityDict = state.entities->Dict.get(entityConfig.name)->Option.getOr(Dict.make())
|
|
484
|
+
Promise.resolve(entityDict->Dict.valuesToArray)
|
|
494
485
|
}
|
|
495
486
|
}
|
|
496
487
|
|
|
@@ -505,36 +496,57 @@ type workerData = {
|
|
|
505
496
|
chainId: int,
|
|
506
497
|
startBlock: int,
|
|
507
498
|
endBlock: option<int>,
|
|
508
|
-
simulate: option<array<
|
|
499
|
+
simulate: option<array<JSON.t>>,
|
|
509
500
|
initialState: Persistence.initialState,
|
|
510
501
|
}
|
|
511
502
|
|
|
512
|
-
let makeCreateTestIndexer = (
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
~allEntities: array<Internal.entityConfig>,
|
|
516
|
-
): (unit => t<'processConfig>) => {
|
|
503
|
+
let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
|
|
504
|
+
unit => t<'processConfig>
|
|
505
|
+
) => {
|
|
517
506
|
() => {
|
|
518
|
-
let
|
|
519
|
-
let
|
|
507
|
+
let allEntities = config.allEntities
|
|
508
|
+
let entities = Dict.make()
|
|
509
|
+
let entityConfigs = Dict.make()
|
|
520
510
|
allEntities->Array.forEach(entityConfig => {
|
|
521
|
-
entities->
|
|
522
|
-
entityConfigs->
|
|
511
|
+
entities->Dict.set(entityConfig.name, Dict.make())
|
|
512
|
+
entityConfigs->Dict.set(entityConfig.name, entityConfig)
|
|
523
513
|
})
|
|
514
|
+
|
|
515
|
+
// Populate config addresses into the entity dict, mirroring PgStorage.initialize
|
|
516
|
+
let envioAddressesDict = entities->Dict.getUnsafe(InternalTable.EnvioAddresses.name)
|
|
517
|
+
config.chainMap
|
|
518
|
+
->ChainMap.values
|
|
519
|
+
->Array.forEach(chainConfig => {
|
|
520
|
+
chainConfig.contracts->Array.forEach(contract => {
|
|
521
|
+
contract.addresses->Array.forEach(
|
|
522
|
+
address => {
|
|
523
|
+
let entity: InternalTable.EnvioAddresses.t = {
|
|
524
|
+
id: Config.EnvioAddresses.makeId(~chainId=chainConfig.id, ~address),
|
|
525
|
+
chainId: chainConfig.id,
|
|
526
|
+
contractName: contract.name,
|
|
527
|
+
registrationBlock: -1,
|
|
528
|
+
registrationLogIndex: -1,
|
|
529
|
+
}
|
|
530
|
+
envioAddressesDict->Dict.set(entity.id, entity->Config.EnvioAddresses.castToInternal)
|
|
531
|
+
},
|
|
532
|
+
)
|
|
533
|
+
})
|
|
534
|
+
})
|
|
535
|
+
|
|
524
536
|
let state = {
|
|
525
537
|
processInProgress: false,
|
|
526
|
-
progressBlockByChain:
|
|
538
|
+
progressBlockByChain: Dict.make(),
|
|
527
539
|
entities,
|
|
528
540
|
entityConfigs,
|
|
529
541
|
processChanges: [],
|
|
530
542
|
}
|
|
531
543
|
|
|
532
544
|
// Build entity operations for each user entity
|
|
533
|
-
let entityOpsDict:
|
|
545
|
+
let entityOpsDict: dict<entityOperations> = Dict.make()
|
|
534
546
|
allEntities->Array.forEach(entityConfig => {
|
|
535
|
-
// Only create ops for user entities (not internal tables like
|
|
536
|
-
if entityConfig.name !== InternalTable.
|
|
537
|
-
entityOpsDict->
|
|
547
|
+
// Only create ops for user entities (not internal tables like envio_addresses)
|
|
548
|
+
if entityConfig.name !== InternalTable.EnvioAddresses.name {
|
|
549
|
+
entityOpsDict->Dict.set(
|
|
538
550
|
entityConfig.name,
|
|
539
551
|
{
|
|
540
552
|
get: makeEntityGet(~state, ~entityConfig),
|
|
@@ -553,7 +565,7 @@ let makeCreateTestIndexer = (
|
|
|
553
565
|
->ChainMap.values
|
|
554
566
|
->Array.forEach(chainConfig => {
|
|
555
567
|
let chainIdStr = chainConfig.id->Int.toString
|
|
556
|
-
chainIds->
|
|
568
|
+
chainIds->Array.push(chainConfig.id)->ignore
|
|
557
569
|
|
|
558
570
|
let chainObj = Utils.Object.createNullObject()
|
|
559
571
|
chainObj
|
|
@@ -582,22 +594,20 @@ let makeCreateTestIndexer = (
|
|
|
582
594
|
enumerable: true,
|
|
583
595
|
get: () => {
|
|
584
596
|
if state.processInProgress {
|
|
585
|
-
|
|
597
|
+
JsError.throwWithMessage(
|
|
586
598
|
`Cannot access ${contract.name}.addresses while indexer.process() is running. ` ++ "Wait for process() to complete before reading contract addresses.",
|
|
587
599
|
)
|
|
588
600
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
// Add accumulated dynamic contract addresses
|
|
592
|
-
switch state.entities->Js.Dict.get(InternalTable.DynamicContractRegistry.name) {
|
|
601
|
+
let addresses = []
|
|
602
|
+
switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
|
|
593
603
|
| Some(dcDict) =>
|
|
594
604
|
dcDict
|
|
595
|
-
->
|
|
605
|
+
->Dict.valuesToArray
|
|
596
606
|
->Array.forEach(
|
|
597
607
|
entity => {
|
|
598
|
-
let dc = entity->
|
|
608
|
+
let dc = entity->castToEnvioAddresses
|
|
599
609
|
if dc.contractName === contract.name && dc.chainId === chainConfig.id {
|
|
600
|
-
addresses->Array.push(dc.
|
|
610
|
+
addresses->Array.push(dc->Config.EnvioAddresses.getAddress)->ignore
|
|
601
611
|
}
|
|
602
612
|
},
|
|
603
613
|
)
|
|
@@ -632,22 +642,22 @@ let makeCreateTestIndexer = (
|
|
|
632
642
|
})
|
|
633
643
|
|
|
634
644
|
// Build the result object with process + entity operations + chain info
|
|
635
|
-
let result:
|
|
636
|
-
result->
|
|
637
|
-
result->
|
|
645
|
+
let result: dict<unknown> = Dict.make()
|
|
646
|
+
result->Dict.set("chainIds", chainIds->(Utils.magic: array<int> => unknown))
|
|
647
|
+
result->Dict.set("chains", chains->(Utils.magic: {..} => unknown))
|
|
638
648
|
entityOpsDict
|
|
639
|
-
->
|
|
649
|
+
->Dict.toArray
|
|
640
650
|
->Array.forEach(((name, ops)) => {
|
|
641
|
-
result->
|
|
651
|
+
result->Dict.set(name, ops->(Utils.magic: entityOperations => unknown))
|
|
642
652
|
})
|
|
643
653
|
|
|
644
|
-
result->
|
|
654
|
+
result->Dict.set(
|
|
645
655
|
"process",
|
|
646
656
|
(
|
|
647
657
|
processConfig => {
|
|
648
658
|
// Check if already processing
|
|
649
659
|
if state.processInProgress {
|
|
650
|
-
|
|
660
|
+
JsError.throwWithMessage(
|
|
651
661
|
"createTestIndexer process is already running. Only one process call is allowed at a time",
|
|
652
662
|
)
|
|
653
663
|
}
|
|
@@ -655,40 +665,40 @@ let makeCreateTestIndexer = (
|
|
|
655
665
|
// Parse and validate processConfig
|
|
656
666
|
let parsedConfig = try processConfig->S.parseOrThrow(processConfigSchema) catch {
|
|
657
667
|
| S.Raised(exn) =>
|
|
658
|
-
|
|
668
|
+
JsError.throwWithMessage(
|
|
659
669
|
`Invalid processConfig: ${exn->Utils.prettifyExn->(Utils.magic: exn => string)}`,
|
|
660
670
|
)
|
|
661
671
|
}
|
|
662
672
|
let rawChains = parsedConfig["chains"]
|
|
663
|
-
let chainKeys = rawChains->
|
|
673
|
+
let chainKeys = rawChains->Dict.keysToArray
|
|
664
674
|
|
|
665
675
|
if chainKeys->Array.length === 0 {
|
|
666
|
-
|
|
676
|
+
JsError.throwWithMessage("createTestIndexer requires at least one chain to be defined")
|
|
667
677
|
}
|
|
668
678
|
|
|
669
679
|
// Sort chain keys by chain ID for deterministic ordering
|
|
670
|
-
let sortedChainKeys =
|
|
671
|
-
|
|
672
|
-
->
|
|
673
|
-
->
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
aId - bId
|
|
677
|
-
})
|
|
680
|
+
let sortedChainKeys = chainKeys->Array.copy
|
|
681
|
+
sortedChainKeys->Array.sort((a, b) => {
|
|
682
|
+
let aId = a->Int.fromString->Option.getOr(0)
|
|
683
|
+
let bId = b->Int.fromString->Option.getOr(0)
|
|
684
|
+
Int.compare(aId, bId)
|
|
685
|
+
})
|
|
678
686
|
|
|
679
687
|
// Parse and validate all chain configs upfront before starting any workers
|
|
680
688
|
let chainEntries = sortedChainKeys->Array.map(chainIdStr => {
|
|
681
|
-
let rawChainConfig = rawChains->
|
|
689
|
+
let rawChainConfig = rawChains->Dict.getUnsafe(chainIdStr)
|
|
682
690
|
let chainId = switch chainIdStr->Int.fromString {
|
|
683
691
|
| Some(id) => id
|
|
684
692
|
| None =>
|
|
685
|
-
|
|
693
|
+
JsError.throwWithMessage(
|
|
694
|
+
`Invalid chain ID "${chainIdStr}": expected a numeric chain ID`,
|
|
695
|
+
)
|
|
686
696
|
}
|
|
687
697
|
let processChainConfig = parseBlockRange(
|
|
688
698
|
~chainIdStr,
|
|
689
699
|
~config,
|
|
690
700
|
~rawChainConfig,
|
|
691
|
-
~progressBlock=state.progressBlockByChain->
|
|
701
|
+
~progressBlock=state.progressBlockByChain->Dict.get(chainIdStr),
|
|
692
702
|
)
|
|
693
703
|
(chainIdStr, chainId, rawChainConfig, processChainConfig)
|
|
694
704
|
})
|
|
@@ -703,26 +713,26 @@ let makeCreateTestIndexer = (
|
|
|
703
713
|
processChainConfig,
|
|
704
714
|
)) => {
|
|
705
715
|
// Build initialState from resolved block range
|
|
706
|
-
let chains:
|
|
707
|
-
chains->
|
|
716
|
+
let chains: dict<chainConfig> = Dict.make()
|
|
717
|
+
chains->Dict.set(chainIdStr, processChainConfig)
|
|
708
718
|
|
|
709
719
|
// Extract dynamic contracts from state.entities for each chain
|
|
710
|
-
let
|
|
711
|
-
switch state.entities->
|
|
720
|
+
let indexingAddressesByChain: dict<array<Internal.indexingAddress>> = Dict.make()
|
|
721
|
+
switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
|
|
712
722
|
| Some(dcDict) =>
|
|
713
723
|
dcDict
|
|
714
|
-
->
|
|
724
|
+
->Dict.valuesToArray
|
|
715
725
|
->Array.forEach(entity => {
|
|
716
|
-
let dc = entity->
|
|
726
|
+
let dc = entity->castToEnvioAddresses
|
|
717
727
|
let dcChainIdStr = dc.chainId->Int.toString
|
|
718
|
-
let contracts = switch
|
|
728
|
+
let contracts = switch indexingAddressesByChain->Dict.get(dcChainIdStr) {
|
|
719
729
|
| Some(arr) => arr
|
|
720
730
|
| None =>
|
|
721
731
|
let arr = []
|
|
722
|
-
|
|
732
|
+
indexingAddressesByChain->Dict.set(dcChainIdStr, arr)
|
|
723
733
|
arr
|
|
724
734
|
}
|
|
725
|
-
contracts->Array.push(dc->
|
|
735
|
+
contracts->Array.push(dc->toIndexingAddress)->ignore
|
|
726
736
|
})
|
|
727
737
|
| None => ()
|
|
728
738
|
}
|
|
@@ -730,7 +740,7 @@ let makeCreateTestIndexer = (
|
|
|
730
740
|
let initialState = makeInitialState(
|
|
731
741
|
~config,
|
|
732
742
|
~processConfigChains=chains,
|
|
733
|
-
~
|
|
743
|
+
~indexingAddressesByChain,
|
|
734
744
|
)
|
|
735
745
|
|
|
736
746
|
Promise.make((resolve, reject) => {
|
|
@@ -745,13 +755,17 @@ let makeCreateTestIndexer = (
|
|
|
745
755
|
NodeJs.WorkerThreads.makeWorker(
|
|
746
756
|
workerPath,
|
|
747
757
|
{
|
|
748
|
-
workerData: workerData->(Utils.magic: workerData =>
|
|
758
|
+
workerData: workerData->(Utils.magic: workerData => JSON.t),
|
|
759
|
+
// Explicitly forward parent env so handlers running in
|
|
760
|
+
// the worker observe the same environment as the test
|
|
761
|
+
// process (e.g. E2E_EXPECTED_END_BLOCK).
|
|
762
|
+
env: %raw(`process.env`),
|
|
749
763
|
},
|
|
750
764
|
)
|
|
751
765
|
} catch {
|
|
752
766
|
| exn =>
|
|
753
767
|
reject(exn->Utils.magic)
|
|
754
|
-
|
|
768
|
+
throw(exn)
|
|
755
769
|
}
|
|
756
770
|
|
|
757
771
|
// Handle messages from worker
|
|
@@ -789,7 +803,7 @@ let makeCreateTestIndexer = (
|
|
|
789
803
|
~checkpointBlockNumbers,
|
|
790
804
|
~checkpointEventsProcessed,
|
|
791
805
|
)
|
|
792
|
-
|
|
806
|
+
JSON.Encode.null->respond
|
|
793
807
|
}
|
|
794
808
|
})
|
|
795
809
|
|
|
@@ -831,21 +845,21 @@ let makeCreateTestIndexer = (
|
|
|
831
845
|
)->(Utils.magic: ('a => promise<processResult>) => unknown),
|
|
832
846
|
)
|
|
833
847
|
|
|
834
|
-
result->(Utils.magic:
|
|
848
|
+
result->(Utils.magic: dict<unknown> => t<'processConfig>)
|
|
835
849
|
}
|
|
836
850
|
}
|
|
837
851
|
|
|
838
|
-
let initTestWorker = (
|
|
852
|
+
let initTestWorker = () => {
|
|
839
853
|
if NodeJs.WorkerThreads.isMainThread {
|
|
840
|
-
|
|
854
|
+
JsError.throwWithMessage("initTestWorker must be called from a worker thread")
|
|
841
855
|
}
|
|
842
856
|
|
|
843
|
-
let parentPort = switch NodeJs.WorkerThreads.parentPort->
|
|
857
|
+
let parentPort = switch NodeJs.WorkerThreads.parentPort->Nullable.toOption {
|
|
844
858
|
| Some(port) => port
|
|
845
|
-
| None =>
|
|
859
|
+
| None => JsError.throwWithMessage("initTestWorker: No parent port available")
|
|
846
860
|
}
|
|
847
861
|
|
|
848
|
-
let workerData: option<workerData> = NodeJs.WorkerThreads.workerData->
|
|
862
|
+
let workerData: option<workerData> = NodeJs.WorkerThreads.workerData->Nullable.toOption
|
|
849
863
|
switch workerData {
|
|
850
864
|
| Some({chainId, startBlock, endBlock, simulate, initialState}) =>
|
|
851
865
|
let chainIdStr = chainId->Int.toString
|
|
@@ -854,29 +868,28 @@ let initTestWorker = (~makeGeneratedConfig: unit => Config.t) => {
|
|
|
854
868
|
let exitAfterFirstEventBlock = endBlock->Option.isNone
|
|
855
869
|
|
|
856
870
|
// Build processConfig JSON for SimulateItems.patchConfig
|
|
857
|
-
let resolvedChainDict:
|
|
858
|
-
resolvedChainDict->
|
|
871
|
+
let resolvedChainDict: dict<unknown> = Dict.make()
|
|
872
|
+
resolvedChainDict->Dict.set("startBlock", startBlock->(Utils.magic: int => unknown))
|
|
859
873
|
switch endBlock {
|
|
860
|
-
| Some(eb) => resolvedChainDict->
|
|
874
|
+
| Some(eb) => resolvedChainDict->Dict.set("endBlock", eb->(Utils.magic: int => unknown))
|
|
861
875
|
| None => ()
|
|
862
876
|
}
|
|
863
877
|
switch simulate {
|
|
864
|
-
| Some(s) =>
|
|
865
|
-
resolvedChainDict->Js.Dict.set("simulate", s->(Utils.magic: array<Js.Json.t> => unknown))
|
|
878
|
+
| Some(s) => resolvedChainDict->Dict.set("simulate", s->(Utils.magic: array<JSON.t> => unknown))
|
|
866
879
|
| None => ()
|
|
867
880
|
}
|
|
868
|
-
let resolvedChainsDict:
|
|
869
|
-
resolvedChainsDict->
|
|
881
|
+
let resolvedChainsDict: dict<unknown> = Dict.make()
|
|
882
|
+
resolvedChainsDict->Dict.set(
|
|
870
883
|
chainIdStr,
|
|
871
|
-
resolvedChainDict->(Utils.magic:
|
|
884
|
+
resolvedChainDict->(Utils.magic: dict<unknown> => unknown),
|
|
872
885
|
)
|
|
873
886
|
let processConfig =
|
|
874
|
-
{"chains": resolvedChainsDict}->(Utils.magic: {"chains":
|
|
887
|
+
{"chains": resolvedChainsDict}->(Utils.magic: {"chains": dict<unknown>} => JSON.t)
|
|
875
888
|
|
|
876
889
|
// Create proxy storage that communicates with main thread
|
|
877
890
|
let proxy = TestIndexerProxyStorage.make(~parentPort, ~initialState)
|
|
878
891
|
let storage = TestIndexerProxyStorage.makeStorage(proxy)
|
|
879
|
-
let config =
|
|
892
|
+
let config = Config.loadWithoutRegistrations()
|
|
880
893
|
let persistence = Persistence.make(
|
|
881
894
|
~userEntities=config.userEntities,
|
|
882
895
|
~allEnums=config.allEnums,
|
|
@@ -899,13 +912,7 @@ let initTestWorker = (~makeGeneratedConfig: unit => Config.t) => {
|
|
|
899
912
|
config
|
|
900
913
|
}
|
|
901
914
|
}
|
|
902
|
-
Main.start(
|
|
903
|
-
~makeGeneratedConfig,
|
|
904
|
-
~persistence,
|
|
905
|
-
~isTest=true,
|
|
906
|
-
~patchConfig,
|
|
907
|
-
~exitAfterFirstEventBlock,
|
|
908
|
-
)->ignore
|
|
915
|
+
Main.start(~persistence, ~isTest=true, ~patchConfig, ~exitAfterFirstEventBlock)->ignore
|
|
909
916
|
| None =>
|
|
910
917
|
Logging.error("TestIndexerWorker: No worker data provided")
|
|
911
918
|
NodeJs.process->NodeJs.exitWithCode(Failure)
|