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/Metrics.res
CHANGED
|
@@ -12,6 +12,8 @@ type chainMetrics = {
|
|
|
12
12
|
startBlock: int,
|
|
13
13
|
endBlock: option<int>,
|
|
14
14
|
numAddresses: int,
|
|
15
|
+
// Per-contract registration counts, in the chain's contract-id order.
|
|
16
|
+
addressesByContract: array<(string, int)>,
|
|
15
17
|
isReady: bool,
|
|
16
18
|
// Raw source height, unlike knownHeight which is clamped to endBlock.
|
|
17
19
|
sourceBlockNumber: int,
|
|
@@ -694,11 +696,23 @@ let renderMetrics = (b: builder, metrics: t) => {
|
|
|
694
696
|
)
|
|
695
697
|
b->series(
|
|
696
698
|
~name="envio_indexing_addresses",
|
|
697
|
-
~help="The number of
|
|
699
|
+
~help="The number of address registrations on chain, static and dynamic. An address shared by N contracts counts N times.",
|
|
698
700
|
~kind="gauge",
|
|
699
701
|
~entries=chains,
|
|
700
702
|
~value=m => m.numAddresses->Int.toFloat,
|
|
701
703
|
)
|
|
704
|
+
b->series(
|
|
705
|
+
~name="envio_indexing_contract_addresses",
|
|
706
|
+
~help="The number of address registrations per contract on chain, static and dynamic. An address shared by N contracts counts N times.",
|
|
707
|
+
~kind="gauge",
|
|
708
|
+
~entries=metrics.chains->Array.flatMap(m =>
|
|
709
|
+
m.addressesByContract->Array.map(((contract, count)) => (
|
|
710
|
+
`{chainId="${m.chainId->ChainId.toString}",contract="${contract->escapeLabelValue}"}`,
|
|
711
|
+
count,
|
|
712
|
+
))
|
|
713
|
+
),
|
|
714
|
+
~value=count => count->Int.toFloat,
|
|
715
|
+
)
|
|
702
716
|
}
|
|
703
717
|
|
|
704
718
|
let contentType = "text/plain; version=0.0.4; charset=utf-8"
|
package/src/Metrics.res.mjs
CHANGED
|
@@ -229,7 +229,11 @@ function renderMetrics(b, metrics) {
|
|
|
229
229
|
series(b, "envio_storage_load_size", "Cumulative number of records loaded from storage during the indexing process.", "counter", storageLoads, s => s.size);
|
|
230
230
|
series(b, "envio_storage_write_seconds", "Cumulative time spent writing batch data to storage.", "counter", storageWrites, s => s.seconds);
|
|
231
231
|
series(b, "envio_storage_write_total", "Cumulative number of successful storage write operations during the indexing process.", "counter", storageWrites, s => s.count);
|
|
232
|
-
series(b, "envio_indexing_addresses", "The number of
|
|
232
|
+
series(b, "envio_indexing_addresses", "The number of address registrations on chain, static and dynamic. An address shared by N contracts counts N times.", "gauge", chains, m => m.numAddresses);
|
|
233
|
+
series(b, "envio_indexing_contract_addresses", "The number of address registrations per contract on chain, static and dynamic. An address shared by N contracts counts N times.", "gauge", metrics.chains.flatMap(m => m.addressesByContract.map(param => [
|
|
234
|
+
`{chainId="` + ChainId.toString(m.chainId) + `",contract="` + escapeLabelValue(param[0]) + `"}`,
|
|
235
|
+
param[1]
|
|
236
|
+
])), count => count);
|
|
233
237
|
}
|
|
234
238
|
|
|
235
239
|
function collect(metrics) {
|
package/src/Persistence.res
CHANGED
|
@@ -27,22 +27,25 @@ type initialChainState = {
|
|
|
27
27
|
numEventsProcessed: float,
|
|
28
28
|
firstEventBlockNumber: option<int>,
|
|
29
29
|
timestampCaughtUpToHeadOrEndblock: option<Date.t>,
|
|
30
|
-
|
|
30
|
+
// Every address the chain indexes, columnar — config-declared and dynamically
|
|
31
|
+
// registered alike. The chain's address store seeds straight from it.
|
|
32
|
+
addressRows: AddressRows.seedRows,
|
|
31
33
|
sourceBlockNumber: int,
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
type initialState = {
|
|
35
37
|
cleanRun: bool,
|
|
38
|
+
// On a resume this is what the database holds, not what the config would
|
|
39
|
+
// derive — the ids must never reshuffle under stored rows.
|
|
40
|
+
contractMapping: ContractMapping.t,
|
|
41
|
+
// Public config snapshot, restored with the address rows. None when
|
|
42
|
+
// envio_info or envio_contracts is missing.
|
|
43
|
+
envioInfo: option<JSON.t>,
|
|
36
44
|
cache: dict<effectCacheRecord>,
|
|
37
45
|
chains: array<initialChainState>,
|
|
38
46
|
checkpointId: Internal.checkpointId,
|
|
39
47
|
// Needed to keep reorg detection logic between restarts
|
|
40
48
|
reorgCheckpoints: array<Internal.reorgCheckpoint>,
|
|
41
|
-
// Public config snapshot read from envio_info, used by `Persistence.init`
|
|
42
|
-
// to compat-check a resume against the running config. None when the
|
|
43
|
-
// schema pre-dates envio_info or the row is missing — `init` treats that
|
|
44
|
-
// as a version mismatch.
|
|
45
|
-
envioInfo: option<JSON.t>,
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
// Carries the already-resolved cache address (`table`) rather than an effect +
|
|
@@ -58,6 +61,9 @@ type updatedEffectCache = {
|
|
|
58
61
|
type rollback = {
|
|
59
62
|
targetCheckpointId: Internal.checkpointId,
|
|
60
63
|
diffCheckpointId: Internal.checkpointId,
|
|
64
|
+
// The address registrations the rollback dropped, as the chains' address
|
|
65
|
+
// stores resolved them. Deleted by primary key in the same transaction.
|
|
66
|
+
rolledBackAddresses: array<AddressRows.key>,
|
|
61
67
|
// Last valid block per chain affected by the rollback. Read by
|
|
62
68
|
// `RollbackCommit.fire` once the diff is durably written.
|
|
63
69
|
progressBlockNumberByChainId: dict<int>,
|
|
@@ -92,6 +98,7 @@ type storage = {
|
|
|
92
98
|
~chainConfigs: array<Config.chain>=?,
|
|
93
99
|
~entities: array<Internal.entityConfig>=?,
|
|
94
100
|
~enums: array<Table.enumConfig<Table.enum>>=?,
|
|
101
|
+
~contractMapping: ContractMapping.t,
|
|
95
102
|
~envioInfo: JSON.t,
|
|
96
103
|
) => promise<initialState>,
|
|
97
104
|
resumeInitialState: unit => promise<initialState>,
|
|
@@ -147,11 +154,13 @@ type storage = {
|
|
|
147
154
|
"new_progress_block_number": int,
|
|
148
155
|
}>,
|
|
149
156
|
>,
|
|
150
|
-
//
|
|
157
|
+
// Rollback data for an entity, as decoded entities rather than storage rows:
|
|
158
|
+
// only the storage knows how it encoded them, so each one decodes its own
|
|
159
|
+
// before handing them back.
|
|
151
160
|
getRollbackData: (
|
|
152
161
|
~entityConfig: Internal.entityConfig,
|
|
153
162
|
~rollbackTargetCheckpointId: Internal.checkpointId,
|
|
154
|
-
) => promise<(array<rollbackRemoval>, array<
|
|
163
|
+
) => promise<(array<rollbackRemoval>, array<Internal.entity>)>,
|
|
155
164
|
// Write batch to storage
|
|
156
165
|
writeBatch: (
|
|
157
166
|
~batch: Batch.t,
|
|
@@ -161,6 +170,8 @@ type storage = {
|
|
|
161
170
|
~allEntities: array<Internal.entityConfig>,
|
|
162
171
|
~updatedEffectsCache: array<updatedEffectCache>,
|
|
163
172
|
~updatedEntities: array<updatedEntity>,
|
|
173
|
+
// Addresses this batch registered, with the checkpoint that covers them.
|
|
174
|
+
~registeredAddresses: array<AddressRows.staged>,
|
|
164
175
|
// Chain metadata stale since the last write, persisted in the same
|
|
165
176
|
// transaction so it never races the batch write.
|
|
166
177
|
~chainMetaData: option<dict<InternalTable.Chains.metaFields>>,
|
|
@@ -194,7 +205,7 @@ let make = (
|
|
|
194
205
|
~allEnums,
|
|
195
206
|
~storage,
|
|
196
207
|
) => {
|
|
197
|
-
let allEntities = userEntities
|
|
208
|
+
let allEntities = userEntities
|
|
198
209
|
let allEnums =
|
|
199
210
|
allEnums->Array.concat([EntityHistory.RowAction.config->Table.fromGenericEnumConfig])
|
|
200
211
|
{
|
|
@@ -207,7 +218,15 @@ let make = (
|
|
|
207
218
|
}
|
|
208
219
|
|
|
209
220
|
let init = {
|
|
210
|
-
async (
|
|
221
|
+
async (
|
|
222
|
+
persistence,
|
|
223
|
+
~chainConfigs,
|
|
224
|
+
~contractMapping,
|
|
225
|
+
~envioInfo,
|
|
226
|
+
~resetCommand,
|
|
227
|
+
~runCommand,
|
|
228
|
+
~reset=false,
|
|
229
|
+
) => {
|
|
211
230
|
try {
|
|
212
231
|
let shouldRun = switch persistence.storageStatus {
|
|
213
232
|
| Unknown => true
|
|
@@ -229,6 +248,7 @@ let init = {
|
|
|
229
248
|
~entities=persistence.allEntities,
|
|
230
249
|
~enums=persistence.allEnums,
|
|
231
250
|
~chainConfigs,
|
|
251
|
+
~contractMapping,
|
|
232
252
|
~envioInfo,
|
|
233
253
|
)
|
|
234
254
|
Logging.info(`The indexer storage is ready. Starting indexing!`)
|
|
@@ -243,17 +263,10 @@ let init = {
|
|
|
243
263
|
) {
|
|
244
264
|
Logging.info(`Found existing indexer storage. Resuming indexing state...`)
|
|
245
265
|
let initialState = await persistence.storage.resumeInitialState()
|
|
246
|
-
// Compat-check the running config against what was stored on the
|
|
247
|
-
// last successful initialize. None means the schema pre-dates
|
|
248
|
-
// envio_info (or the row was wiped out-of-band) and we can't
|
|
249
|
-
// compare — treat it as a version mismatch.
|
|
250
266
|
let changedPaths = switch initialState.envioInfo {
|
|
251
|
-
| None => ["
|
|
267
|
+
| None => ["storage was initialized by an older envio version"]
|
|
252
268
|
| Some(stored) => Config.diffPaths(~stored, ~current=envioInfo)
|
|
253
269
|
}
|
|
254
|
-
// `storage.clickhouse` is serialized as a plain bool by the
|
|
255
|
-
// public config (see Rust `StorageConfig`), so probe for
|
|
256
|
-
// `Boolean(true)`, not an object.
|
|
257
270
|
let hasClickhouse = switch envioInfo {
|
|
258
271
|
| Object(d) =>
|
|
259
272
|
switch d->Dict.get("storage") {
|
|
@@ -267,6 +280,9 @@ let init = {
|
|
|
267
280
|
| _ => false
|
|
268
281
|
}
|
|
269
282
|
Config.throwIfIncompatible(changedPaths, ~resetCommand, ~runCommand, ~hasClickhouse)
|
|
283
|
+
if !(initialState.contractMapping->ContractMapping.isEqual(contractMapping)) {
|
|
284
|
+
Config.throwIfIncompatible(["contracts"], ~resetCommand, ~runCommand, ~hasClickhouse)
|
|
285
|
+
}
|
|
270
286
|
persistence.storageStatus = Ready(initialState)
|
|
271
287
|
let progress = Dict.make()
|
|
272
288
|
initialState.chains->Array.forEach(c => {
|
package/src/Persistence.res.mjs
CHANGED
|
@@ -5,23 +5,23 @@ import * as Logging from "./Logging.res.mjs";
|
|
|
5
5
|
import * as EntityHistory from "./db/EntityHistory.res.mjs";
|
|
6
6
|
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
7
7
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
8
|
+
import * as ContractMapping from "./ContractMapping.res.mjs";
|
|
8
9
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
9
10
|
|
|
10
11
|
let StorageError = /* @__PURE__ */Primitive_exceptions.create("Persistence.StorageError");
|
|
11
12
|
|
|
12
13
|
function make(userEntities, allEnums, storage) {
|
|
13
|
-
let allEntities = userEntities.concat([Config.EnvioAddresses.entityConfig]);
|
|
14
14
|
let allEnums$1 = allEnums.concat([EntityHistory.RowAction.config]);
|
|
15
15
|
return {
|
|
16
16
|
userEntities: userEntities,
|
|
17
|
-
allEntities:
|
|
17
|
+
allEntities: userEntities,
|
|
18
18
|
allEnums: allEnums$1,
|
|
19
19
|
storageStatus: "Unknown",
|
|
20
20
|
storage: storage
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
async function init(persistence, chainConfigs, envioInfo, resetCommand, runCommand, resetOpt) {
|
|
24
|
+
async function init(persistence, chainConfigs, contractMapping, envioInfo, resetCommand, runCommand, resetOpt) {
|
|
25
25
|
let reset = resetOpt !== undefined ? resetOpt : false;
|
|
26
26
|
try {
|
|
27
27
|
let promise = persistence.storageStatus;
|
|
@@ -49,7 +49,7 @@ async function init(persistence, chainConfigs, envioInfo, resetCommand, runComma
|
|
|
49
49
|
};
|
|
50
50
|
if (reset || !await persistence.storage.isInitialized()) {
|
|
51
51
|
Logging.info(`Initializing the indexer storage...`);
|
|
52
|
-
let initialState = await persistence.storage.initialize(chainConfigs, persistence.allEntities, persistence.allEnums, envioInfo);
|
|
52
|
+
let initialState = await persistence.storage.initialize(chainConfigs, persistence.allEntities, persistence.allEnums, contractMapping, envioInfo);
|
|
53
53
|
Logging.info(`The indexer storage is ready. Starting indexing!`);
|
|
54
54
|
persistence.storageStatus = {
|
|
55
55
|
TAG: "Ready",
|
|
@@ -63,7 +63,7 @@ async function init(persistence, chainConfigs, envioInfo, resetCommand, runComma
|
|
|
63
63
|
Logging.info(`Found existing indexer storage. Resuming indexing state...`);
|
|
64
64
|
let initialState$1 = await persistence.storage.resumeInitialState();
|
|
65
65
|
let stored = initialState$1.envioInfo;
|
|
66
|
-
let changedPaths = stored !== undefined ? Config.diffPaths(stored, envioInfo) : ["
|
|
66
|
+
let changedPaths = stored !== undefined ? Config.diffPaths(stored, envioInfo) : ["storage was initialized by an older envio version"];
|
|
67
67
|
let hasClickhouse;
|
|
68
68
|
if (typeof envioInfo === "object" && envioInfo !== null && !Array.isArray(envioInfo)) {
|
|
69
69
|
let match$1 = envioInfo["storage"];
|
|
@@ -77,6 +77,9 @@ async function init(persistence, chainConfigs, envioInfo, resetCommand, runComma
|
|
|
77
77
|
hasClickhouse = false;
|
|
78
78
|
}
|
|
79
79
|
Config.throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhouse);
|
|
80
|
+
if (!ContractMapping.isEqual(initialState$1.contractMapping, contractMapping)) {
|
|
81
|
+
Config.throwIfIncompatible(["contracts"], resetCommand, runCommand, hasClickhouse);
|
|
82
|
+
}
|
|
80
83
|
persistence.storageStatus = {
|
|
81
84
|
TAG: "Ready",
|
|
82
85
|
_0: initialState$1
|