envio 3.7.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.
- package/README.md +2 -2
- package/index.d.ts +399 -156
- package/package.json +6 -6
- package/src/AddressRows.res +121 -0
- package/src/AddressRows.res.mjs +143 -0
- package/src/Batch.res +2 -0
- package/src/Batch.res.mjs +2 -1
- package/src/ChainState.res +82 -68
- package/src/ChainState.res.mjs +81 -65
- package/src/ChainState.resi +14 -9
- package/src/Config.res +41 -91
- package/src/Config.res.mjs +34 -68
- package/src/ContractMapping.res +66 -0
- package/src/ContractMapping.res.mjs +73 -0
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +4 -0
- package/src/Envio.res +54 -76
- package/src/EventConfigBuilder.res +157 -30
- package/src/EventConfigBuilder.res.mjs +118 -24
- package/src/FetchState.res +59 -67
- package/src/FetchState.res.mjs +34 -44
- package/src/HandlerRegister.res +20 -11
- package/src/HandlerRegister.res.mjs +22 -5
- package/src/Hasura.res +30 -22
- package/src/Hasura.res.mjs +11 -5
- package/src/InMemoryStore.res +18 -36
- package/src/InMemoryStore.res.mjs +12 -26
- package/src/IndexerState.res +21 -1
- package/src/IndexerState.res.mjs +9 -3
- package/src/IndexerState.resi +1 -0
- package/src/Internal.res +33 -13
- package/src/Internal.res.mjs +12 -16
- package/src/Main.res +27 -20
- package/src/Main.res.mjs +19 -14
- package/src/MemoryStorage.res +78 -73
- package/src/MemoryStorage.res.mjs +66 -81
- package/src/Metrics.res +15 -1
- package/src/Metrics.res.mjs +5 -1
- package/src/Persistence.res +34 -18
- package/src/Persistence.res.mjs +8 -5
- package/src/PgStorage.res +189 -66
- package/src/PgStorage.res.mjs +93 -59
- package/src/Rollback.res +14 -10
- package/src/Rollback.res.mjs +4 -2
- package/src/SimulateItems.res +254 -9
- package/src/SimulateItems.res.mjs +214 -47
- package/src/TestIndexer.res +119 -121
- package/src/TestIndexer.res.mjs +95 -100
- package/src/Utils.res +7 -0
- package/src/Utils.res.mjs +9 -2
- package/src/Writing.res +2 -0
- package/src/Writing.res.mjs +2 -1
- package/src/bindings/ClickHouse.res +39 -6
- package/src/bindings/ClickHouse.res.mjs +29 -4
- package/src/bindings/NodeJs.res +9 -0
- package/src/bindings/NodeJs.res.mjs +8 -1
- package/src/bindings/Postgres.res +9 -0
- package/src/bindings/Postgres.res.mjs +3 -0
- package/src/db/EntityHistory.res +12 -18
- package/src/db/EntityHistory.res.mjs +3 -14
- package/src/db/InternalTable.res +182 -65
- package/src/db/InternalTable.res.mjs +183 -73
- package/src/db/Table.res +24 -0
- package/src/db/Table.res.mjs +20 -1
- package/src/sources/AddressSet.res +0 -22
- package/src/sources/AddressStore.res +48 -88
- package/src/sources/AddressStore.res.mjs +11 -22
- package/src/sources/EvmHyperSyncSource.res +3 -2
- package/src/sources/SimulateSource.res +8 -4
- package/src/sources/SimulateSource.res.mjs +7 -3
- package/src/sources/Svm.res +34 -7
- package/src/sources/Svm.res.mjs +32 -4
- package/src/sources/SvmHyperSyncClient.res +24 -30
- package/src/sources/SvmHyperSyncClient.res.mjs +3 -2
- package/src/sources/SvmHyperSyncSource.res +88 -36
- package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
- package/src/sources/TransactionStore.res +38 -0
- package/src/sources/TransactionStore.res.mjs +5 -0
- package/svm.schema.json +37 -82
package/src/Main.res.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import * as Process from "process";
|
|
|
13
13
|
import * as ChainMap from "./ChainMap.res.mjs";
|
|
14
14
|
import * as PgStorage from "./PgStorage.res.mjs";
|
|
15
15
|
import * as ChainState from "./ChainState.res.mjs";
|
|
16
|
+
import * as AddressRows from "./AddressRows.res.mjs";
|
|
16
17
|
import * as EnvioGlobal from "./EnvioGlobal.res.mjs";
|
|
17
18
|
import * as IndexerLoop from "./IndexerLoop.res.mjs";
|
|
18
19
|
import * as Persistence from "./Persistence.res.mjs";
|
|
@@ -24,6 +25,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
24
25
|
import * as Helpers from "yargs/helpers";
|
|
25
26
|
import * as RollbackCommit from "./RollbackCommit.res.mjs";
|
|
26
27
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
28
|
+
import * as ContractMapping from "./ContractMapping.res.mjs";
|
|
27
29
|
import * as HandlerRegister from "./HandlerRegister.res.mjs";
|
|
28
30
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
29
31
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
@@ -94,7 +96,7 @@ function setGlobalPersistence(persistence) {
|
|
|
94
96
|
EnvioGlobal.value.persistence = Primitive_option.some(persistence);
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
function
|
|
99
|
+
function getInitialState() {
|
|
98
100
|
let persistence = EnvioGlobal.value.persistence;
|
|
99
101
|
if (persistence === undefined) {
|
|
100
102
|
return;
|
|
@@ -103,10 +105,14 @@ function getInitialChainState(chainId) {
|
|
|
103
105
|
if (typeof initialState !== "object" || initialState.TAG === "Initializing") {
|
|
104
106
|
return;
|
|
105
107
|
} else {
|
|
106
|
-
return initialState._0
|
|
108
|
+
return initialState._0;
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
function getInitialChainState(chainId) {
|
|
113
|
+
return Stdlib_Option.flatMap(getInitialState(), initialState => initialState.chains.find(c => c.id === chainId));
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
function buildChainsObject(config) {
|
|
111
117
|
let chainIds = [];
|
|
112
118
|
let chains = Object.create(null);
|
|
@@ -178,18 +184,16 @@ function buildChainsObject(config) {
|
|
|
178
184
|
let chainState = IndexerState.getChainState(Primitive_option.valFromOption(state), chainConfig.id);
|
|
179
185
|
return ChainState.contractAddresses(chainState, contract.name);
|
|
180
186
|
}
|
|
181
|
-
let
|
|
182
|
-
if (
|
|
187
|
+
let initialState = getInitialState();
|
|
188
|
+
if (initialState === undefined) {
|
|
189
|
+
return contract.addresses;
|
|
190
|
+
}
|
|
191
|
+
let chainState$1 = initialState.chains.find(c => c.id === chainConfig.id);
|
|
192
|
+
if (chainState$1 !== undefined) {
|
|
193
|
+
return AddressRows.renderOfContract(chainState$1.addressRows, config.ecosystem.name, !config.lowercaseAddresses, ContractMapping.idOfOrThrow(initialState.contractMapping, contract.name, undefined));
|
|
194
|
+
} else {
|
|
183
195
|
return contract.addresses;
|
|
184
196
|
}
|
|
185
|
-
let addresses = contract.addresses.slice();
|
|
186
|
-
chainState$1.indexingAddresses.forEach(dc => {
|
|
187
|
-
if (dc.contractName === contract.name) {
|
|
188
|
-
addresses.push(dc.address);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
return addresses;
|
|
193
197
|
}
|
|
194
198
|
});
|
|
195
199
|
Object.defineProperty(chainObj, contract.name, {
|
|
@@ -463,7 +467,7 @@ function getEnvioInfo() {
|
|
|
463
467
|
async function migrate(reset) {
|
|
464
468
|
let config = Config.load();
|
|
465
469
|
let persistence = PgStorage.makePersistenceFromConfig(config, undefined);
|
|
466
|
-
await Persistence.init(persistence, ChainMap.values(config.chainMap), Config.stripSensitiveData(Config.getPublicConfigJson()), "envio local db-migrate setup", undefined, reset);
|
|
470
|
+
await Persistence.init(persistence, ChainMap.values(config.chainMap), config.contractMapping, Config.stripSensitiveData(Config.getPublicConfigJson()), "envio local db-migrate setup", undefined, reset);
|
|
467
471
|
return await persistence.storage.close();
|
|
468
472
|
}
|
|
469
473
|
|
|
@@ -490,7 +494,7 @@ async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockO
|
|
|
490
494
|
let isDevelopmentMode = !isTest && config.isDev;
|
|
491
495
|
let persistence$1 = persistence !== undefined ? persistence : PgStorage.makePersistenceFromConfig(config, undefined);
|
|
492
496
|
EnvioGlobal.value.persistence = Primitive_option.some(persistence$1);
|
|
493
|
-
await Persistence.init(persistence$1, ChainMap.values(config.chainMap), Config.stripSensitiveData(Config.getPublicConfigJson()), isDevelopmentMode ? "envio dev -r" : "envio start -r", isDevelopmentMode ? "envio dev" : "envio start", reset);
|
|
497
|
+
await Persistence.init(persistence$1, ChainMap.values(config.chainMap), config.contractMapping, Config.stripSensitiveData(Config.getPublicConfigJson()), isDevelopmentMode ? "envio dev -r" : "envio start -r", isDevelopmentMode ? "envio dev" : "envio start", reset);
|
|
494
498
|
let registrationsByChainId = await HandlerLoader.registerAllHandlers(config);
|
|
495
499
|
let config$1;
|
|
496
500
|
if (isTest) {
|
|
@@ -552,6 +556,7 @@ export {
|
|
|
552
556
|
setIndexerState,
|
|
553
557
|
getGlobalPersistence,
|
|
554
558
|
setGlobalPersistence,
|
|
559
|
+
getInitialState,
|
|
555
560
|
getInitialChainState,
|
|
556
561
|
buildChainsObject,
|
|
557
562
|
getGlobalIndexer,
|
package/src/MemoryStorage.res
CHANGED
|
@@ -49,6 +49,7 @@ type t = {
|
|
|
49
49
|
cache: dict<Persistence.effectCacheRecord>,
|
|
50
50
|
effectCache: dict<dict<Internal.effectCacheItem>>,
|
|
51
51
|
mutable envioInfo: option<JSON.t>,
|
|
52
|
+
addresses: AddressRows.Table.t,
|
|
52
53
|
mutable isInitialized: bool,
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -61,6 +62,7 @@ let make = (): t => {
|
|
|
61
62
|
cache: Dict.make(),
|
|
62
63
|
effectCache: Dict.make(),
|
|
63
64
|
envioInfo: None,
|
|
65
|
+
addresses: AddressRows.Table.make(),
|
|
64
66
|
isInitialized: false,
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -117,61 +119,23 @@ let registerEntities = (state: t, ~entities: array<Internal.entityConfig>) =>
|
|
|
117
119
|
|
|
118
120
|
// Seeds the config's contract addresses, mirroring what PgStorage.initialize
|
|
119
121
|
// writes into `envio_addresses`.
|
|
120
|
-
let
|
|
121
|
-
|
|
122
|
-
chainConfigs
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
registrationLogIndex: -1,
|
|
132
|
-
}
|
|
133
|
-
dict->Dict.set(entity.id, entity->Config.EnvioAddresses.castToInternal)
|
|
134
|
-
},
|
|
135
|
-
)
|
|
136
|
-
)
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
external castToEnvioAddresses: Internal.entity => InternalTable.EnvioAddresses.t = "%identity"
|
|
141
|
-
|
|
142
|
-
let toIndexingAddress = (dc: InternalTable.EnvioAddresses.t): Internal.indexingAddress => {
|
|
143
|
-
address: dc->Config.EnvioAddresses.getAddress,
|
|
144
|
-
contractName: dc.contractName,
|
|
145
|
-
registrationBlock: dc.registrationBlock,
|
|
122
|
+
let seedConfigAddresses = (
|
|
123
|
+
state: t,
|
|
124
|
+
~chainConfigs: array<Config.chain>,
|
|
125
|
+
~contractMapping,
|
|
126
|
+
~ecosystem,
|
|
127
|
+
) => {
|
|
128
|
+
// Initialize starts from an empty schema — the Postgres DDL drops and
|
|
129
|
+
// recreates one — so a re-initialize must not stack a second copy of the
|
|
130
|
+
// config's addresses on what a previous one left behind.
|
|
131
|
+
state.addresses->AddressRows.Table.clear
|
|
132
|
+
state.addresses->ChainState.seedConfigAddresses(~chainConfigs, ~ecosystem, ~contractMapping)
|
|
146
133
|
}
|
|
147
134
|
|
|
148
|
-
|
|
149
|
-
// chain id string, derived from the envio_addresses entities.
|
|
150
|
-
let getIndexingAddressesByChain = (state: t): dict<array<Internal.indexingAddress>> => {
|
|
151
|
-
let byChain = Dict.make()
|
|
152
|
-
switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
|
|
153
|
-
| Some(dcDict) =>
|
|
154
|
-
dcDict
|
|
155
|
-
->Dict.valuesToArray
|
|
156
|
-
->Array.forEach(entity => {
|
|
157
|
-
let dc = entity->castToEnvioAddresses
|
|
158
|
-
let chainIdStr = dc.chainId->ChainId.toString
|
|
159
|
-
let contracts = switch byChain->Dict.get(chainIdStr) {
|
|
160
|
-
| Some(arr) => arr
|
|
161
|
-
| None =>
|
|
162
|
-
let arr = []
|
|
163
|
-
byChain->Dict.set(chainIdStr, arr)
|
|
164
|
-
arr
|
|
165
|
-
}
|
|
166
|
-
contracts->Array.push(dc->toIndexingAddress)->ignore
|
|
167
|
-
})
|
|
168
|
-
| None => ()
|
|
169
|
-
}
|
|
170
|
-
byChain
|
|
171
|
-
}
|
|
135
|
+
let addressRowsByChain = (state: t) => state.addresses->AddressRows.Table.groupByChain
|
|
172
136
|
|
|
173
137
|
let toInitialChainStates = (state: t): array<Persistence.initialChainState> => {
|
|
174
|
-
let addressesByChain = state->
|
|
138
|
+
let addressesByChain = state->addressRowsByChain
|
|
175
139
|
state.chains
|
|
176
140
|
->Dict.valuesToArray
|
|
177
141
|
->Array.map((chain): Persistence.initialChainState => {
|
|
@@ -183,9 +147,9 @@ let toInitialChainStates = (state: t): array<Persistence.initialChainState> => {
|
|
|
183
147
|
numEventsProcessed: chain.numEventsProcessed,
|
|
184
148
|
firstEventBlockNumber: chain.firstEventBlockNumber,
|
|
185
149
|
timestampCaughtUpToHeadOrEndblock: chain.timestampCaughtUpToHeadOrEndblock,
|
|
186
|
-
|
|
187
|
-
->Dict.
|
|
188
|
-
->Option.getOr(
|
|
150
|
+
addressRows: addressesByChain
|
|
151
|
+
->Utils.Dict.dangerouslyGetNonOption(chain.id->ChainId.toString)
|
|
152
|
+
->Option.getOr(AddressRows.emptySeedRows()),
|
|
189
153
|
sourceBlockNumber: chain.sourceBlockNumber,
|
|
190
154
|
})
|
|
191
155
|
}
|
|
@@ -220,23 +184,37 @@ let reorgCheckpoints = (state: t): array<Internal.reorgCheckpoint> =>
|
|
|
220
184
|
}
|
|
221
185
|
)
|
|
222
186
|
|
|
223
|
-
let toInitialState = (state: t, ~cleanRun): Persistence.initialState => {
|
|
187
|
+
let toInitialState = (state: t, ~cleanRun, ~contractMapping): Persistence.initialState => {
|
|
224
188
|
cleanRun,
|
|
189
|
+
contractMapping,
|
|
190
|
+
envioInfo: state.envioInfo,
|
|
225
191
|
cache: state.cache,
|
|
226
192
|
chains: state->toInitialChainStates,
|
|
227
193
|
checkpointId: state->committedCheckpointId,
|
|
228
194
|
reorgCheckpoints: state->reorgCheckpoints,
|
|
229
|
-
envioInfo: state.envioInfo,
|
|
230
195
|
}
|
|
231
196
|
|
|
232
197
|
let handleLoad = (state: t, ~tableName: string, ~filter: EntityFilter.t): array<
|
|
233
198
|
Internal.entity,
|
|
234
199
|
> => {
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
200
|
+
// Effect caches (`envio_effect_<name>`) are loaded through the same call, and
|
|
201
|
+
// they have no entity config — they're served from the cache `writeBatch`
|
|
202
|
+
// filled, so a resumed indexer reuses cached outputs instead of recomputing
|
|
203
|
+
// them the way Postgres would.
|
|
238
204
|
switch state.entityConfigs->Dict.get(tableName) {
|
|
239
|
-
| None =>
|
|
205
|
+
| None =>
|
|
206
|
+
switch state.effectCache->Dict.get(tableName) {
|
|
207
|
+
| None => []
|
|
208
|
+
| Some(cacheDict) =>
|
|
209
|
+
cacheDict
|
|
210
|
+
->Dict.valuesToArray
|
|
211
|
+
->Array.filter(item =>
|
|
212
|
+
filter->EntityFilter.matches(
|
|
213
|
+
~entity=item->(Utils.magic: Internal.effectCacheItem => dict<EntityFilter.FieldValue.t>),
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
->(Utils.magic: array<Internal.effectCacheItem> => array<Internal.entity>)
|
|
217
|
+
}
|
|
240
218
|
| Some(entityConfig) =>
|
|
241
219
|
let entityDict = state.entities->Dict.get(entityConfig.name)->Option.getOr(Dict.make())
|
|
242
220
|
let matched =
|
|
@@ -292,8 +270,10 @@ let backfillHistory = (
|
|
|
292
270
|
}
|
|
293
271
|
}
|
|
294
272
|
|
|
295
|
-
let applyRollback = (state: t, ~targetCheckpointId) => {
|
|
273
|
+
let applyRollback = (state: t, ~targetCheckpointId, ~rolledBackAddresses) => {
|
|
296
274
|
state.checkpoints = state.checkpoints->Array.filter(cp => cp.id <= targetCheckpointId)
|
|
275
|
+
// Addresses are removed by primary key, exactly like the Postgres delete.
|
|
276
|
+
rolledBackAddresses->Array.forEach(key => state.addresses->AddressRows.Table.delete(key))
|
|
297
277
|
state.history
|
|
298
278
|
->Dict.toArray
|
|
299
279
|
->Array.forEach(((name, rows)) =>
|
|
@@ -308,6 +288,7 @@ let writeBatch = (
|
|
|
308
288
|
~isInReorgThreshold,
|
|
309
289
|
~config: Config.t,
|
|
310
290
|
~updatedEntities: array<Persistence.updatedEntity>,
|
|
291
|
+
~registeredAddresses: array<AddressRows.staged>,
|
|
311
292
|
~updatedEffectsCache: array<Persistence.updatedEffectCache>,
|
|
312
293
|
~chainMetaData: option<dict<InternalTable.Chains.metaFields>>,
|
|
313
294
|
) => {
|
|
@@ -316,10 +297,24 @@ let writeBatch = (
|
|
|
316
297
|
// Rollback first, exactly like the Postgres transaction: the batch being
|
|
317
298
|
// written is the reprocessed one, so its rows must land on the reverted state.
|
|
318
299
|
switch rollback {
|
|
319
|
-
| Some({targetCheckpointId}) =>
|
|
300
|
+
| Some({targetCheckpointId, rolledBackAddresses}) =>
|
|
301
|
+
state->applyRollback(~targetCheckpointId, ~rolledBackAddresses)
|
|
320
302
|
| None => ()
|
|
321
303
|
}
|
|
322
304
|
|
|
305
|
+
registeredAddresses->Array.forEach(({row}) => state.addresses->AddressRows.Table.insert(row))
|
|
306
|
+
|
|
307
|
+
// The rollback diff restates what the reverted state already is, so it is not
|
|
308
|
+
// a change history should record — and an id it touches needs no backfill
|
|
309
|
+
// either, because the diff already carries its reverted value. Postgres draws
|
|
310
|
+
// the same line, keyed on the diff's checkpoint id.
|
|
311
|
+
let diffCheckpointId = rollback->Option.map(({diffCheckpointId}) => diffCheckpointId)
|
|
312
|
+
let isDiff = (change: Change.t<Internal.entity>) =>
|
|
313
|
+
switch diffCheckpointId {
|
|
314
|
+
| Some(diffCheckpointId) => change->Change.getCheckpointId === diffCheckpointId
|
|
315
|
+
| None => false
|
|
316
|
+
}
|
|
317
|
+
|
|
323
318
|
updatedEntities->Array.forEach(({entityConfig, scope, changes}: Persistence.updatedEntity) => {
|
|
324
319
|
let entityDict = state->getEntityDict(~name=entityConfig.name)
|
|
325
320
|
let historyRows = state->getHistory(~name=entityConfig.name)
|
|
@@ -327,9 +322,17 @@ let writeBatch = (
|
|
|
327
322
|
// onto the stored entity the same way the Postgres write path does.
|
|
328
323
|
let chainIdField = entityConfig.table->Table.getChainIdField
|
|
329
324
|
|
|
325
|
+
let idsWithDiff = Utils.Set.make()
|
|
326
|
+
changes->Array.forEach(change =>
|
|
327
|
+
if isDiff(change) {
|
|
328
|
+
idsWithDiff->Utils.Set.add(change->Change.getEntityId->EntityId.toKey)->ignore
|
|
329
|
+
}
|
|
330
|
+
)
|
|
331
|
+
|
|
330
332
|
changes->Array.forEach(change => {
|
|
331
333
|
let entityId = change->Change.getEntityId
|
|
332
|
-
|
|
334
|
+
let shouldSaveChangeHistory = shouldSaveHistory && !isDiff(change)
|
|
335
|
+
if shouldSaveHistory && !(idsWithDiff->Utils.Set.has(entityId->EntityId.toKey)) {
|
|
333
336
|
state->backfillHistory(~entityConfig, ~scope, ~entityId, ~rows=historyRows)
|
|
334
337
|
}
|
|
335
338
|
switch change {
|
|
@@ -340,7 +343,7 @@ let writeBatch = (
|
|
|
340
343
|
| _ => entity
|
|
341
344
|
}
|
|
342
345
|
entityDict->Dict.set(rowKey(~scope, ~entityId), storedEntity)
|
|
343
|
-
if
|
|
346
|
+
if shouldSaveChangeHistory {
|
|
344
347
|
historyRows
|
|
345
348
|
->Array.push({
|
|
346
349
|
entityId,
|
|
@@ -353,7 +356,7 @@ let writeBatch = (
|
|
|
353
356
|
}
|
|
354
357
|
| Delete({checkpointId}) =>
|
|
355
358
|
entityDict->Utils.Dict.deleteInPlace(rowKey(~scope, ~entityId))
|
|
356
|
-
if
|
|
359
|
+
if shouldSaveChangeHistory {
|
|
357
360
|
historyRows
|
|
358
361
|
->Array.push({
|
|
359
362
|
entityId,
|
|
@@ -471,8 +474,7 @@ let getRollbackData = (
|
|
|
471
474
|
->ignore
|
|
472
475
|
| Some({action: DELETE, entityId, scope}) =>
|
|
473
476
|
removals->Array.push({Persistence.entityId, scope})->ignore
|
|
474
|
-
| Some({action: SET, entity: Some(entity)}) =>
|
|
475
|
-
restored->Array.push(entity->(Utils.magic: Internal.entity => unknown))->ignore
|
|
477
|
+
| Some({action: SET, entity: Some(entity)}) => restored->Array.push(entity)->ignore
|
|
476
478
|
| Some({action: SET, entity: None}) => ()
|
|
477
479
|
}
|
|
478
480
|
})
|
|
@@ -521,9 +523,9 @@ let getRollbackProgressDiff = (state: t, ~rollbackTargetCheckpointId) => {
|
|
|
521
523
|
let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
522
524
|
name: "memory",
|
|
523
525
|
isInitialized: async () => state.isInitialized,
|
|
524
|
-
initialize: async (~chainConfigs=[], ~entities=[], ~enums as _=[], ~envioInfo) => {
|
|
526
|
+
initialize: async (~chainConfigs=[], ~entities=[], ~enums as _=[], ~contractMapping, ~envioInfo) => {
|
|
525
527
|
state->registerEntities(~entities)
|
|
526
|
-
state->
|
|
528
|
+
state->seedConfigAddresses(~chainConfigs, ~contractMapping, ~ecosystem=config.ecosystem.name)
|
|
527
529
|
chainConfigs->Array.forEach(chainConfig =>
|
|
528
530
|
state.chains->Dict.set(
|
|
529
531
|
chainConfig.id->ChainId.toString,
|
|
@@ -543,9 +545,10 @@ let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
|
543
545
|
)
|
|
544
546
|
state.envioInfo = Some(envioInfo)
|
|
545
547
|
state.isInitialized = true
|
|
546
|
-
state->toInitialState(~cleanRun=true)
|
|
548
|
+
state->toInitialState(~cleanRun=true, ~contractMapping)
|
|
547
549
|
},
|
|
548
|
-
resumeInitialState: async () =>
|
|
550
|
+
resumeInitialState: async () =>
|
|
551
|
+
state->toInitialState(~cleanRun=false, ~contractMapping=config.contractMapping),
|
|
549
552
|
loadOrThrow: async (~filter, ~table: Table.table) =>
|
|
550
553
|
state
|
|
551
554
|
->handleLoad(~tableName=table.tableName, ~filter)
|
|
@@ -562,14 +565,14 @@ let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
|
562
565
|
),
|
|
563
566
|
dumpEffectCache: async () => (),
|
|
564
567
|
reset: async () => {
|
|
565
|
-
let clear =
|
|
566
|
-
dict->Dict.keysToArray->Array.forEach(key => dict->Utils.Dict.deleteInPlace(key))
|
|
568
|
+
let clear = Utils.Dict.clearInPlace
|
|
567
569
|
state.entities->clear
|
|
568
570
|
state.history->clear
|
|
569
571
|
state.chains->clear
|
|
570
572
|
state.effectCache->clear
|
|
571
573
|
state.cache->clear
|
|
572
574
|
state.checkpoints = []
|
|
575
|
+
state.addresses->AddressRows.Table.clear
|
|
573
576
|
state.envioInfo = None
|
|
574
577
|
state.isInitialized = false
|
|
575
578
|
},
|
|
@@ -648,6 +651,7 @@ let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
|
648
651
|
~allEntities as _,
|
|
649
652
|
~updatedEffectsCache,
|
|
650
653
|
~updatedEntities,
|
|
654
|
+
~registeredAddresses,
|
|
651
655
|
~chainMetaData,
|
|
652
656
|
~onWrite as _,
|
|
653
657
|
) =>
|
|
@@ -657,6 +661,7 @@ let toStorage = (state: t, ~config: Config.t): Persistence.storage => {
|
|
|
657
661
|
~isInReorgThreshold,
|
|
658
662
|
~config,
|
|
659
663
|
~updatedEntities,
|
|
664
|
+
~registeredAddresses,
|
|
660
665
|
~updatedEffectsCache,
|
|
661
666
|
~chainMetaData,
|
|
662
667
|
),
|
|
@@ -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
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
});
|
|
82
|
+
function seedConfigAddresses(state, chainConfigs, contractMapping, ecosystem) {
|
|
83
|
+
AddressRows.Table.clear(state.addresses);
|
|
84
|
+
ChainState.seedConfigAddresses(state.addresses, chainConfigs, ecosystem, contractMapping);
|
|
98
85
|
}
|
|
99
86
|
|
|
100
|
-
function
|
|
101
|
-
return
|
|
102
|
-
address: Config.EnvioAddresses.getAddress(dc),
|
|
103
|
-
contractName: dc.contract_name,
|
|
104
|
-
registrationBlock: dc.registration_block
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
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 =
|
|
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
|
-
|
|
102
|
+
addressRows: Stdlib_Option.getOr(addressesByChain[ChainId.toString(chain.id)], AddressRows.emptySeedRows()),
|
|
141
103
|
sourceBlockNumber: chain.sourceBlockNumber
|
|
142
104
|
}));
|
|
143
105
|
}
|
|
@@ -174,33 +136,39 @@ 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
|
|
|
188
151
|
function handleLoad(state, tableName, filter) {
|
|
189
152
|
let entityConfig = state.entityConfigs[tableName];
|
|
190
|
-
if (entityConfig
|
|
191
|
-
|
|
153
|
+
if (entityConfig !== undefined) {
|
|
154
|
+
let entityDict = Stdlib_Option.getOr(state.entities[entityConfig.name], {});
|
|
155
|
+
let matched = Object.values(entityDict).filter(entity => EntityFilter.matches(filter, entity));
|
|
156
|
+
let field = Table.getChainIdField(entityConfig.table);
|
|
157
|
+
if (field !== undefined) {
|
|
158
|
+
return matched.map(entity => {
|
|
159
|
+
let copy = Utils.Dict.shallowCopy(entity);
|
|
160
|
+
Utils.Dict.deleteInPlace(copy, field.fieldName);
|
|
161
|
+
return copy;
|
|
162
|
+
});
|
|
163
|
+
} else {
|
|
164
|
+
return matched;
|
|
165
|
+
}
|
|
192
166
|
}
|
|
193
|
-
let
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (field !== undefined) {
|
|
197
|
-
return matched.map(entity => {
|
|
198
|
-
let copy = Utils.Dict.shallowCopy(entity);
|
|
199
|
-
Utils.Dict.deleteInPlace(copy, field.fieldName);
|
|
200
|
-
return copy;
|
|
201
|
-
});
|
|
167
|
+
let cacheDict = state.effectCache[tableName];
|
|
168
|
+
if (cacheDict !== undefined) {
|
|
169
|
+
return Object.values(cacheDict).filter(item => EntityFilter.matches(filter, item));
|
|
202
170
|
} else {
|
|
203
|
-
return
|
|
171
|
+
return [];
|
|
204
172
|
}
|
|
205
173
|
}
|
|
206
174
|
|
|
@@ -222,27 +190,46 @@ function backfillHistory(state, entityConfig, scope, entityId, rows) {
|
|
|
222
190
|
}
|
|
223
191
|
}
|
|
224
192
|
|
|
225
|
-
function applyRollback(state, targetCheckpointId) {
|
|
193
|
+
function applyRollback(state, targetCheckpointId, rolledBackAddresses) {
|
|
226
194
|
state.checkpoints = state.checkpoints.filter(cp => cp.id <= targetCheckpointId);
|
|
195
|
+
rolledBackAddresses.forEach(key => AddressRows.Table.$$delete(state.addresses, key));
|
|
227
196
|
Object.entries(state.history).forEach(param => {
|
|
228
197
|
state.history[param[0]] = param[1].filter(row => row.checkpointId <= targetCheckpointId);
|
|
229
198
|
});
|
|
230
199
|
}
|
|
231
200
|
|
|
232
|
-
function writeBatch(state, batch, rollback, isInReorgThreshold, config, updatedEntities, updatedEffectsCache, chainMetaData) {
|
|
201
|
+
function writeBatch(state, batch, rollback, isInReorgThreshold, config, updatedEntities, registeredAddresses, updatedEffectsCache, chainMetaData) {
|
|
233
202
|
let shouldSaveHistory = Config.shouldSaveHistory(config, isInReorgThreshold);
|
|
234
203
|
if (rollback !== undefined) {
|
|
235
|
-
applyRollback(state, rollback.targetCheckpointId);
|
|
204
|
+
applyRollback(state, rollback.targetCheckpointId, rollback.rolledBackAddresses);
|
|
236
205
|
}
|
|
206
|
+
registeredAddresses.forEach(param => AddressRows.Table.insert(state.addresses, param.row));
|
|
207
|
+
let diffCheckpointId = Stdlib_Option.map(rollback, param => param.diffCheckpointId);
|
|
208
|
+
let isDiff = change => {
|
|
209
|
+
if (diffCheckpointId !== undefined) {
|
|
210
|
+
return change.checkpointId === diffCheckpointId;
|
|
211
|
+
} else {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
237
215
|
updatedEntities.forEach(param => {
|
|
216
|
+
let changes = param.changes;
|
|
238
217
|
let scope = param.scope;
|
|
239
218
|
let entityConfig = param.entityConfig;
|
|
240
219
|
let entityDict = getEntityDict(state, entityConfig.name);
|
|
241
220
|
let historyRows = getHistory(state, entityConfig.name);
|
|
242
221
|
let chainIdField = Table.getChainIdField(entityConfig.table);
|
|
243
|
-
|
|
222
|
+
let idsWithDiff = new Set();
|
|
223
|
+
changes.forEach(change => {
|
|
224
|
+
if (isDiff(change)) {
|
|
225
|
+
idsWithDiff.add(EntityId.toKey(change.entityId));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
changes.forEach(change => {
|
|
244
230
|
let entityId = change.entityId;
|
|
245
|
-
|
|
231
|
+
let shouldSaveChangeHistory = shouldSaveHistory && !isDiff(change);
|
|
232
|
+
if (shouldSaveHistory && !idsWithDiff.has(EntityId.toKey(entityId))) {
|
|
246
233
|
backfillHistory(state, entityConfig, scope, entityId, historyRows);
|
|
247
234
|
}
|
|
248
235
|
if (change.type === "SET") {
|
|
@@ -250,7 +237,7 @@ function writeBatch(state, batch, rollback, isInReorgThreshold, config, updatedE
|
|
|
250
237
|
let match = Internal.chainScopeChainId(scope);
|
|
251
238
|
let storedEntity = chainIdField !== undefined && match !== undefined ? Internal.stampChainId(entity, chainIdField.fieldName, Primitive_option.valFromOption(match)) : entity;
|
|
252
239
|
entityDict[rowKey(scope, entityId)] = storedEntity;
|
|
253
|
-
if (
|
|
240
|
+
if (shouldSaveChangeHistory) {
|
|
254
241
|
historyRows.push({
|
|
255
242
|
entityId: entityId,
|
|
256
243
|
scope: scope,
|
|
@@ -264,7 +251,7 @@ function writeBatch(state, batch, rollback, isInReorgThreshold, config, updatedE
|
|
|
264
251
|
}
|
|
265
252
|
}
|
|
266
253
|
Utils.Dict.deleteInPlace(entityDict, rowKey(scope, entityId));
|
|
267
|
-
if (
|
|
254
|
+
if (shouldSaveChangeHistory) {
|
|
268
255
|
historyRows.push({
|
|
269
256
|
entityId: entityId,
|
|
270
257
|
scope: scope,
|
|
@@ -409,12 +396,12 @@ function toStorage(state, config) {
|
|
|
409
396
|
return {
|
|
410
397
|
name: "memory",
|
|
411
398
|
isInitialized: async () => state.isInitialized,
|
|
412
|
-
initialize: async (chainConfigsOpt, entitiesOpt, $staropt$star, envioInfo) => {
|
|
399
|
+
initialize: async (chainConfigsOpt, entitiesOpt, $staropt$star, contractMapping, envioInfo) => {
|
|
413
400
|
let chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
|
|
414
401
|
let entities = entitiesOpt !== undefined ? entitiesOpt : [];
|
|
415
402
|
$staropt$star !== undefined;
|
|
416
403
|
registerEntities(state, entities);
|
|
417
|
-
|
|
404
|
+
seedConfigAddresses(state, chainConfigs, contractMapping, config.ecosystem.name);
|
|
418
405
|
chainConfigs.forEach(chainConfig => {
|
|
419
406
|
state.chains[ChainId.toString(chainConfig.id)] = {
|
|
420
407
|
id: chainConfig.id,
|
|
@@ -431,9 +418,9 @@ function toStorage(state, config) {
|
|
|
431
418
|
});
|
|
432
419
|
state.envioInfo = envioInfo;
|
|
433
420
|
state.isInitialized = true;
|
|
434
|
-
return toInitialState(state, true);
|
|
421
|
+
return toInitialState(state, true, contractMapping);
|
|
435
422
|
},
|
|
436
|
-
resumeInitialState: async () => toInitialState(state, false),
|
|
423
|
+
resumeInitialState: async () => toInitialState(state, false, config.contractMapping),
|
|
437
424
|
loadOrThrow: async (filter, table) => handleLoad(state, table.tableName, filter),
|
|
438
425
|
ensureQueryIndexes: async (param, param$1) => {},
|
|
439
426
|
ensureSchemaIndexes: async param => {},
|
|
@@ -448,15 +435,14 @@ function toStorage(state, config) {
|
|
|
448
435
|
},
|
|
449
436
|
dumpEffectCache: async () => {},
|
|
450
437
|
reset: async () => {
|
|
451
|
-
let clear =
|
|
452
|
-
Object.keys(dict).forEach(key => Utils.Dict.deleteInPlace(dict, key));
|
|
453
|
-
};
|
|
438
|
+
let clear = Utils.Dict.clearInPlace;
|
|
454
439
|
clear(state.entities);
|
|
455
440
|
clear(state.history);
|
|
456
441
|
clear(state.chains);
|
|
457
442
|
clear(state.effectCache);
|
|
458
443
|
clear(state.cache);
|
|
459
444
|
state.checkpoints = [];
|
|
445
|
+
AddressRows.Table.clear(state.addresses);
|
|
460
446
|
state.envioInfo = undefined;
|
|
461
447
|
state.isInitialized = false;
|
|
462
448
|
},
|
|
@@ -517,7 +503,7 @@ function toStorage(state, config) {
|
|
|
517
503
|
}),
|
|
518
504
|
getRollbackProgressDiff: async rollbackTargetCheckpointId => getRollbackProgressDiff(state, rollbackTargetCheckpointId),
|
|
519
505
|
getRollbackData: async (entityConfig, rollbackTargetCheckpointId) => getRollbackData(state, entityConfig, rollbackTargetCheckpointId),
|
|
520
|
-
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),
|
|
521
507
|
close: async () => {}
|
|
522
508
|
};
|
|
523
509
|
}
|
|
@@ -579,9 +565,8 @@ export {
|
|
|
579
565
|
getEntityDict,
|
|
580
566
|
getHistory,
|
|
581
567
|
registerEntities,
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
getIndexingAddressesByChain,
|
|
568
|
+
seedConfigAddresses,
|
|
569
|
+
addressRowsByChain,
|
|
585
570
|
toInitialChainStates,
|
|
586
571
|
committedCheckpointId,
|
|
587
572
|
reorgCheckpoints,
|