envio 3.11.0 → 3.12.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/index.d.ts +3 -0
- package/package.json +6 -6
- package/src/Batch.res +111 -78
- package/src/Batch.res.mjs +53 -46
- package/src/BatchProcessing.res +1 -11
- package/src/BatchProcessing.res.mjs +1 -4
- package/src/ChainState.res +72 -19
- package/src/ChainState.res.mjs +50 -12
- package/src/ChainState.resi +5 -0
- package/src/Config.res +58 -37
- package/src/Config.res.mjs +63 -53
- package/src/CrossChainState.res +49 -52
- package/src/CrossChainState.res.mjs +25 -23
- package/src/CrossChainState.resi +6 -13
- package/src/EffectState.res +13 -4
- package/src/EffectState.resi +7 -1
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +6 -6
- package/src/FetchState.res +14 -0
- package/src/FetchState.res.mjs +14 -0
- package/src/FinalizeBackfill.res +16 -12
- package/src/FinalizeBackfill.res.mjs +3 -3
- package/src/HistoryPolicy.res +46 -0
- package/src/HistoryPolicy.res.mjs +50 -0
- package/src/InMemoryStore.res +30 -32
- package/src/InMemoryStore.res.mjs +33 -28
- package/src/IndexerState.res +66 -45
- package/src/IndexerState.res.mjs +57 -29
- package/src/IndexerState.resi +8 -13
- package/src/Internal.res +4 -2
- package/src/LoadLayer.res +11 -4
- package/src/LoadLayer.res.mjs +8 -5
- package/src/Main.res +25 -24
- package/src/Main.res.mjs +24 -25
- package/src/Metrics.res +49 -1
- package/src/Metrics.res.mjs +26 -3
- package/src/Persistence.res +55 -16
- package/src/Persistence.res.mjs +18 -3
- package/src/PgStorage.res +194 -118
- package/src/PgStorage.res.mjs +132 -72
- package/src/PruneStaleHistory.res +9 -15
- package/src/PruneStaleHistory.res.mjs +11 -20
- package/src/Rollback.res +9 -14
- package/src/Rollback.res.mjs +5 -3
- package/src/Sink.res +7 -5
- package/src/Sink.res.mjs +4 -4
- package/src/Staging.res +298 -0
- package/src/Staging.res.mjs +257 -0
- package/src/TestIndexer.res +5 -5
- package/src/TestIndexer.res.mjs +7 -6
- package/src/UserContext.res +7 -4
- package/src/UserContext.res.mjs +5 -2
- package/src/Utils.res +9 -0
- package/src/Utils.res.mjs +9 -0
- package/src/Writing.res +34 -20
- package/src/Writing.res.mjs +15 -20
- package/src/bindings/ClickHouse.res +41 -34
- package/src/bindings/ClickHouse.res.mjs +36 -30
- package/src/bindings/ClickHouseSink.res +45 -186
- package/src/bindings/ClickHouseSink.res.mjs +21 -174
- package/src/db/CheckpointSequence.res +109 -0
- package/src/db/CheckpointSequence.res.mjs +99 -0
- package/src/db/EntityHistory.res +6 -5
- package/src/db/EntityHistory.res.mjs +5 -5
- package/src/db/Frontier.res +86 -0
- package/src/db/Frontier.res.mjs +126 -0
- package/src/db/InternalTable.res +145 -27
- package/src/db/InternalTable.res.mjs +115 -29
- package/src/db/RollbackFloors.res +34 -41
- package/src/db/RollbackFloors.res.mjs +27 -71
- package/src/sources/BlockStore.res +3 -0
- package/src/sources/EvmHyperSyncSource.res +3 -1
- package/src/sources/EvmHyperSyncSource.res.mjs +2 -1
- package/src/sources/HyperSync.res +2 -0
- package/src/sources/HyperSync.res.mjs +1 -0
- package/src/sources/HyperSync.resi +1 -0
- package/src/sources/HyperSyncClient.res +3 -0
- package/src/sources/RequestStat.res +8 -1
- package/src/sources/Source.res +4 -3
- package/src/sources/SourceManager.res +30 -10
- package/src/sources/SourceManager.res.mjs +24 -7
- package/src/sources/SourceManager.resi +2 -0
- package/src/tui/Tui.res +56 -143
- package/src/tui/Tui.res.mjs +70 -166
- package/src/tui/components/TuiData.res +61 -16
- package/src/tui/components/TuiData.res.mjs +53 -15
- package/svm.schema.json +0 -7
- package/src/db/CheckpointBounds.res +0 -53
- package/src/db/CheckpointBounds.res.mjs +0 -44
package/src/PgStorage.res.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import * as Schema from "./db/Schema.res.mjs";
|
|
|
12
12
|
import * as ChainId from "./ChainId.res.mjs";
|
|
13
13
|
import * as Logging from "./Logging.res.mjs";
|
|
14
14
|
import * as EntityId from "./EntityId.res.mjs";
|
|
15
|
+
import * as Frontier from "./db/Frontier.res.mjs";
|
|
15
16
|
import * as Internal from "./Internal.res.mjs";
|
|
16
17
|
import Postgres from "postgres";
|
|
17
18
|
import * as ChainState from "./ChainState.res.mjs";
|
|
@@ -22,6 +23,7 @@ import * as IndexCatalog from "./db/IndexCatalog.res.mjs";
|
|
|
22
23
|
import * as IndexManager from "./db/IndexManager.res.mjs";
|
|
23
24
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
24
25
|
import * as EntityHistory from "./db/EntityHistory.res.mjs";
|
|
26
|
+
import * as HistoryPolicy from "./HistoryPolicy.res.mjs";
|
|
25
27
|
import * as InternalTable from "./db/InternalTable.res.mjs";
|
|
26
28
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
27
29
|
import * as Child_process from "child_process";
|
|
@@ -29,10 +31,10 @@ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
|
29
31
|
import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
|
|
30
32
|
import * as ContractMapping from "./ContractMapping.res.mjs";
|
|
31
33
|
import * as IndexDefinition from "./db/IndexDefinition.res.mjs";
|
|
32
|
-
import * as CheckpointBounds from "./db/CheckpointBounds.res.mjs";
|
|
33
34
|
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
34
35
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
35
36
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
37
|
+
import * as CheckpointSequence from "./db/CheckpointSequence.res.mjs";
|
|
36
38
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
37
39
|
|
|
38
40
|
function makeClient() {
|
|
@@ -57,7 +59,25 @@ function formatSeconds(timeRef) {
|
|
|
57
59
|
|
|
58
60
|
let slowOnLargeDatabaseNotice = "This can take a long time on a large database.";
|
|
59
61
|
|
|
60
|
-
function
|
|
62
|
+
function partitionTableName(entityConfig, chainId) {
|
|
63
|
+
let chainIdStr = ChainId.toString(chainId);
|
|
64
|
+
return Table.fitPgTableName(entityConfig.table.tableName + `$` + chainIdStr, `$` + entityConfig.index.toString() + `$` + chainIdStr);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function indexTableNames(entityConfig, partitionChainIds) {
|
|
68
|
+
let match = Table.getChainIdField(entityConfig.table);
|
|
69
|
+
if (match !== undefined) {
|
|
70
|
+
if (partitionChainIds !== undefined) {
|
|
71
|
+
return partitionChainIds.map(chainId => partitionTableName(entityConfig, chainId));
|
|
72
|
+
} else {
|
|
73
|
+
return [entityConfig.table.tableName];
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
return [entityConfig.table.tableName];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getSchemaIndexes(entities, partitionChainIds) {
|
|
61
81
|
let derivedSchema = Schema.make(entities.map(e => e.table));
|
|
62
82
|
let all = [];
|
|
63
83
|
entities.forEach(param => {
|
|
@@ -76,6 +96,10 @@ function getSchemaIndexes(entities) {
|
|
|
76
96
|
});
|
|
77
97
|
});
|
|
78
98
|
let seen = new Set();
|
|
99
|
+
let entityByTableName = {};
|
|
100
|
+
entities.forEach(entityConfig => {
|
|
101
|
+
entityByTableName[entityConfig.table.tableName] = entityConfig;
|
|
102
|
+
});
|
|
79
103
|
return all.filter(definition => {
|
|
80
104
|
let key = IndexDefinition.key(definition);
|
|
81
105
|
if (seen.has(key)) {
|
|
@@ -84,7 +108,11 @@ function getSchemaIndexes(entities) {
|
|
|
84
108
|
seen.add(key);
|
|
85
109
|
return true;
|
|
86
110
|
}
|
|
87
|
-
})
|
|
111
|
+
}).flatMap(definition => indexTableNames(Stdlib_Option.getOrThrow(entityByTableName[definition.tableName], undefined), partitionChainIds).map(tableName => ({
|
|
112
|
+
tableName: tableName,
|
|
113
|
+
columns: definition.columns,
|
|
114
|
+
method: definition.method
|
|
115
|
+
})));
|
|
88
116
|
}
|
|
89
117
|
|
|
90
118
|
function makeCreateTableQuery(table, pgSchema, isNumericArrayAsText, chainIdModeOpt, partitionByColumn) {
|
|
@@ -108,11 +136,6 @@ function makeCreateTableQuery(table, pgSchema, isNumericArrayAsText, chainIdMode
|
|
|
108
136
|
) + `;`;
|
|
109
137
|
}
|
|
110
138
|
|
|
111
|
-
function partitionTableName(entityConfig, chainId) {
|
|
112
|
-
let chainIdStr = ChainId.toString(chainId);
|
|
113
|
-
return Table.fitPgTableName(entityConfig.table.tableName + `$` + chainIdStr, `$` + entityConfig.index.toString() + `$` + chainIdStr);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
139
|
let rowSchemaCache = new WeakMap();
|
|
117
140
|
|
|
118
141
|
function getRowSchema(entityConfig) {
|
|
@@ -228,7 +251,7 @@ function makeCreateEntityTableQueries(entityConfig, pgSchema, isNumericArrayAsTe
|
|
|
228
251
|
).concat([createTable(getEntityHistory(entityConfig).table, undefined)]);
|
|
229
252
|
}
|
|
230
253
|
|
|
231
|
-
function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigsOpt, entitiesOpt, enumsOpt, isEmptyPgSchemaOpt, deferSchemaIndexesOpt, chainIdModeOpt) {
|
|
254
|
+
function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, checkpointSequence, chainConfigsOpt, entitiesOpt, enumsOpt, isEmptyPgSchemaOpt, deferSchemaIndexesOpt, chainIdModeOpt) {
|
|
232
255
|
let chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
|
|
233
256
|
let entities = entitiesOpt !== undefined ? entitiesOpt : [];
|
|
234
257
|
let enums = enumsOpt !== undefined ? enumsOpt : [];
|
|
@@ -240,12 +263,12 @@ function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfi
|
|
|
240
263
|
InternalTable.EnvioInfo.table,
|
|
241
264
|
InternalTable.EnvioContracts.table,
|
|
242
265
|
InternalTable.EnvioAddresses.table,
|
|
243
|
-
InternalTable.Checkpoints.
|
|
266
|
+
InternalTable.Checkpoints.tableFor(checkpointSequence),
|
|
244
267
|
InternalTable.RawEvents.table
|
|
245
268
|
];
|
|
246
269
|
let chainIds = chainConfigs.map(chainConfig => chainConfig.id);
|
|
247
270
|
let tableQueries = generalTables.map(table => makeCreateTableQuery(table, pgSchema, isHasuraEnabled, chainIdMode, undefined)).concat(entities.flatMap(entityConfig => makeCreateEntityTableQueries(entityConfig, pgSchema, isHasuraEnabled, chainIdMode, chainIds)));
|
|
248
|
-
let schemaIndexes = getSchemaIndexes(entities);
|
|
271
|
+
let schemaIndexes = getSchemaIndexes(entities, undefined);
|
|
249
272
|
let query = {
|
|
250
273
|
contents: (
|
|
251
274
|
isEmptyPgSchema && pgSchema === "public" ? `CREATE SCHEMA IF NOT EXISTS "` + pgSchema + `";\n` : `DROP SCHEMA IF EXISTS "` + pgSchema + `" CASCADE;
|
|
@@ -687,10 +710,29 @@ function executeSet(sql, items, dbFunction) {
|
|
|
687
710
|
}
|
|
688
711
|
}
|
|
689
712
|
|
|
690
|
-
|
|
713
|
+
function pickCheckpoints(column, picked) {
|
|
714
|
+
if (typeof picked !== "object") {
|
|
715
|
+
return column;
|
|
716
|
+
} else {
|
|
717
|
+
return picked._0.map(index => column[index]);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
async function writeBatch(sql, batch, pgSchema, rollback, config, allEntities, setEffectCacheOrThrow, setQueryCache, updatedEffectsCache, updatedEntities, registeredAddresses, sinkPromise, chainMetaData, escapeTables) {
|
|
691
722
|
try {
|
|
692
723
|
let chainIdMode = config.chainIdMode;
|
|
693
|
-
let
|
|
724
|
+
let indexes = Stdlib_Array.filterMapWithIndex(batch.checkpointChainIds, (chainId, index) => {
|
|
725
|
+
if (HistoryPolicy.forChain(batch.history, chainId)) {
|
|
726
|
+
return index;
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
let pickedCheckpoints = Utils.$$Array.isEmpty(indexes) ? undefined : (
|
|
730
|
+
indexes.length === batch.checkpointIds.length ? "AllCheckpoints" : ({
|
|
731
|
+
TAG: "CheckpointIndexes",
|
|
732
|
+
_0: indexes
|
|
733
|
+
})
|
|
734
|
+
);
|
|
735
|
+
let writtenFrontier = Persistence.writtenFrontier(batch, rollback);
|
|
694
736
|
let specificError = {
|
|
695
737
|
contents: undefined
|
|
696
738
|
};
|
|
@@ -725,6 +767,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
725
767
|
}
|
|
726
768
|
};
|
|
727
769
|
let setEntities = updatedEntities.map(param => {
|
|
770
|
+
let shouldSaveHistory = param.shouldSaveHistory;
|
|
728
771
|
let changes = param.changes;
|
|
729
772
|
let scope = param.scope;
|
|
730
773
|
let entityConfig = param.entityConfig;
|
|
@@ -732,7 +775,6 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
732
775
|
let idsToDelete = [];
|
|
733
776
|
let scopeChainId;
|
|
734
777
|
scopeChainId = scope === "crossChain" ? undefined : Primitive_option.some(scope);
|
|
735
|
-
let shouldSaveHistory = Config.shouldSaveHistory(config, isInReorgThreshold, scopeChainId);
|
|
736
778
|
let match = Table.getChainIdField(entityConfig.table);
|
|
737
779
|
let changes$1;
|
|
738
780
|
if (match !== undefined && scopeChainId !== undefined) {
|
|
@@ -756,7 +798,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
756
798
|
let chainIdParams = match$1 !== undefined ? (
|
|
757
799
|
scopeChainId !== undefined ? [Primitive_option.valFromOption(scopeChainId)] : []
|
|
758
800
|
) : [];
|
|
759
|
-
let diffCheckpointId = Stdlib_Option.
|
|
801
|
+
let diffCheckpointId = Stdlib_Option.flatMap(rollback, r => CheckpointSequence.findForScope(config.checkpointSequence, r.diffFrontier, scope));
|
|
760
802
|
let batchSetUpdates = [];
|
|
761
803
|
let batchDeleteEntityIds = [];
|
|
762
804
|
let batchDeleteCheckpointIds = [];
|
|
@@ -872,6 +914,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
872
914
|
sql => InternalTable.Chains.setProgressedChains(sql, pgSchema, Utils.Dict.mapValuesToArray(batch.progressedChainsById, chainAfterBatch => ({
|
|
873
915
|
chainId: chainAfterBatch.fetchState.chainId,
|
|
874
916
|
progressBlockNumber: chainAfterBatch.progressBlockNumber,
|
|
917
|
+
progressBlockTime: chainAfterBatch.progressBlockTime,
|
|
875
918
|
sourceBlockNumber: chainAfterBatch.sourceBlockNumber,
|
|
876
919
|
totalEventsProcessed: chainAfterBatch.totalEventsProcessed
|
|
877
920
|
}))),
|
|
@@ -883,8 +926,11 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
883
926
|
if (Utils.$$Array.notEmpty(registeredAddresses)) {
|
|
884
927
|
setOperations.push(sql => InternalTable.EnvioAddresses.insert(sql, pgSchema, registeredAddresses.map(staged => staged.row), chainIdMode));
|
|
885
928
|
}
|
|
886
|
-
if (
|
|
887
|
-
setOperations.push(sql => InternalTable.
|
|
929
|
+
if (!Utils.Dict.isEmpty(writtenFrontier)) {
|
|
930
|
+
setOperations.push(sql => InternalTable.Chains.setCheckpointFrontier(sql, pgSchema, writtenFrontier, chainIdMode));
|
|
931
|
+
}
|
|
932
|
+
if (pickedCheckpoints !== undefined) {
|
|
933
|
+
setOperations.push(sql => InternalTable.Checkpoints.insert(sql, pgSchema, pickCheckpoints(batch.checkpointIds, pickedCheckpoints), pickCheckpoints(batch.checkpointChainIds, pickedCheckpoints), pickCheckpoints(batch.checkpointBlockNumbers, pickedCheckpoints), pickCheckpoints(batch.checkpointBlockHashes, pickedCheckpoints), pickCheckpoints(batch.checkpointEventsProcessed, pickedCheckpoints), chainIdMode));
|
|
888
934
|
}
|
|
889
935
|
await Promise.all(setOperations.map(dbFunc => dbFunc(sql)));
|
|
890
936
|
if (sinkPromise === undefined) {
|
|
@@ -913,7 +959,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
913
959
|
if (exn$1.RE_EXN_ID === PgEncodingError) {
|
|
914
960
|
let escapeTables$1 = escapeTables !== undefined ? Primitive_option.valFromOption(escapeTables) : new Set();
|
|
915
961
|
escapeTables$1.add(exn$1.table);
|
|
916
|
-
return await writeBatch(sql, batch, pgSchema, rollback,
|
|
962
|
+
return await writeBatch(sql, batch, pgSchema, rollback, config, allEntities, setEffectCacheOrThrow, setQueryCache, updatedEffectsCache, updatedEntities, registeredAddresses, sinkPromise, chainMetaData, Primitive_option.some(escapeTables$1));
|
|
917
963
|
}
|
|
918
964
|
throw exn$1;
|
|
919
965
|
}
|
|
@@ -943,7 +989,7 @@ function makeGetRollbackPreTargetRowsQuery(entityConfig, pgSchema, floors) {
|
|
|
943
989
|
let keyColumns = rollbackKeyColumns(entityConfig);
|
|
944
990
|
let keyColumnsCommaSeparated = keyColumns.map(c => tableRef + `."` + c + `"`).join(", ");
|
|
945
991
|
let keyMatch = keyColumns.map(c => `h."` + c + `" = ` + tableRef + `."` + c + `"`).join(" AND ");
|
|
946
|
-
let bounds =
|
|
992
|
+
let bounds = CheckpointSequence.sql(floors.checkpointBounds, Table.getPgChainIdColumn(entityConfig.table), tableRef);
|
|
947
993
|
return `SELECT DISTINCT ON (` + keyColumnsCommaSeparated + `) ` + dataFieldsCommaSeparated + `, ` + tableRef + `."` + EntityHistory.changeFieldName + `"
|
|
948
994
|
FROM "` + pgSchema + `"."` + historyTableName + `"` + bounds.join + `
|
|
949
995
|
WHERE ` + tableRef + `."` + EntityHistory.checkpointIdFieldName + `" <= ` + bounds.checkpointId + `
|
|
@@ -961,7 +1007,7 @@ function makeGetRollbackRemovedIdsQuery(entityConfig, pgSchema, floors) {
|
|
|
961
1007
|
let tableRef = `"` + historyTableName + `"`;
|
|
962
1008
|
let keyColumns = rollbackKeyColumns(entityConfig);
|
|
963
1009
|
let keyMatch = keyColumns.map(c => `h."` + c + `" = ` + tableRef + `."` + c + `"`).join(" AND ");
|
|
964
|
-
let bounds =
|
|
1010
|
+
let bounds = CheckpointSequence.sql(floors.checkpointBounds, Table.getPgChainIdColumn(entityConfig.table), tableRef);
|
|
965
1011
|
return `SELECT DISTINCT ` + keyColumns.map(c => tableRef + `."` + c + `"`).join(", ") + `
|
|
966
1012
|
FROM "` + pgSchema + `"."` + historyTableName + `"` + bounds.join + `
|
|
967
1013
|
WHERE ` + tableRef + `."` + EntityHistory.checkpointIdFieldName + `" > ` + bounds.checkpointId + `
|
|
@@ -982,8 +1028,9 @@ let rollbackChainIdSchema = Utils.$$WeakMap.memoize(table => Stdlib_Option.map(T
|
|
|
982
1028
|
|
|
983
1029
|
let rollbackRemovedIdSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.object(s => s.f(Table.idFieldName, Table.getIdSchema(table))));
|
|
984
1030
|
|
|
985
|
-
function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isHasuraEnabled, chainIdModeOpt, ecosystem, sink,
|
|
1031
|
+
function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isHasuraEnabled, chainIdModeOpt, ecosystem, sink, isolatedOpt, onInitialize) {
|
|
986
1032
|
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
1033
|
+
let isolated = isolatedOpt !== undefined ? isolatedOpt : false;
|
|
987
1034
|
let containerName = "envio-postgres";
|
|
988
1035
|
let psqlExecOptions_env = Object.fromEntries([
|
|
989
1036
|
[
|
|
@@ -1107,9 +1154,6 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1107
1154
|
}
|
|
1108
1155
|
}
|
|
1109
1156
|
let cacheTableInfo = await queryCacheTableInfo();
|
|
1110
|
-
if (withUpload && Utils.$$Array.notEmpty(cacheTableInfo) && onNewTables !== undefined) {
|
|
1111
|
-
await onNewTables(cacheTableInfo.map(info => info.table_name));
|
|
1112
|
-
}
|
|
1113
1157
|
let cache = {};
|
|
1114
1158
|
cacheTableInfo.forEach(param => {
|
|
1115
1159
|
let tableName = param.table_name;
|
|
@@ -1138,7 +1182,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1138
1182
|
if (sink !== undefined) {
|
|
1139
1183
|
await sink.initialize(entities);
|
|
1140
1184
|
}
|
|
1141
|
-
let queries = makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigs, pgEntities, enums, Utils.$$Array.isEmpty(schemaTableNames), true, chainIdMode);
|
|
1185
|
+
let queries = makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, CheckpointSequence.fromEntities(entities), chainConfigs, pgEntities, enums, Utils.$$Array.isEmpty(schemaTableNames), true, chainIdMode);
|
|
1142
1186
|
let rowsByChain = chainConfigs.map(chainConfig => ChainState.configStorageRows(chainConfig, ecosystem, contractMapping));
|
|
1143
1187
|
let configAddressRows = rowsByChain.flat();
|
|
1144
1188
|
await sql.begin(async sql => {
|
|
@@ -1165,13 +1209,14 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1165
1209
|
endBlock: chainConfig.endBlock,
|
|
1166
1210
|
maxReorgDepth: chainConfig.maxReorgDepth,
|
|
1167
1211
|
progressBlockNumber: -1,
|
|
1212
|
+
progressBlockTime: undefined,
|
|
1168
1213
|
numEventsProcessed: 0,
|
|
1169
1214
|
firstEventBlockNumber: undefined,
|
|
1170
1215
|
timestampCaughtUpToHeadOrEndblock: undefined,
|
|
1171
1216
|
addressRows: AddressRows.seedRowsOf(rowsByChain[idx]),
|
|
1172
1217
|
sourceBlockNumber: 0
|
|
1173
1218
|
})),
|
|
1174
|
-
|
|
1219
|
+
checkpointFrontier: Frontier.empty(),
|
|
1175
1220
|
reorgCheckpoints: []
|
|
1176
1221
|
};
|
|
1177
1222
|
};
|
|
@@ -1246,10 +1291,23 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1246
1291
|
}
|
|
1247
1292
|
return IndexManager.resync(indexManager, name, rows);
|
|
1248
1293
|
};
|
|
1249
|
-
let
|
|
1250
|
-
|
|
1294
|
+
let partitionChainIds = chainIds => {
|
|
1295
|
+
if (isolated) {
|
|
1296
|
+
return Primitive_option.some(chainIds);
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1299
|
+
let queryTableName = (entityConfig, scope) => {
|
|
1300
|
+
if (scope === "crossChain") {
|
|
1301
|
+
return entityConfig.table.tableName;
|
|
1302
|
+
} else {
|
|
1303
|
+
return indexTableNames(entityConfig, partitionChainIds([scope]))[0];
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
let ensureQueryIndexes = async (entityConfig, scope, filters) => {
|
|
1307
|
+
let tableName = queryTableName(entityConfig, scope);
|
|
1308
|
+
let columns = filterColumns(entityConfig.table, filters);
|
|
1251
1309
|
await Promise.all(columns.map(column => {
|
|
1252
|
-
let definition = IndexDefinition.single(
|
|
1310
|
+
let definition = IndexDefinition.single(tableName, column);
|
|
1253
1311
|
return Stdlib_Promise.$$catch(IndexManager.ensure(indexManager, definition, "LeadingColumns", async () => {
|
|
1254
1312
|
let prepared = IndexManager.prepare(indexManager, definition, "LeadingColumns", pgSchema);
|
|
1255
1313
|
if (prepared === undefined) {
|
|
@@ -1258,7 +1316,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1258
1316
|
let verb = prepared.isRebuild ? "Rebuilding unusable index" : "Creating index";
|
|
1259
1317
|
Logging.info({
|
|
1260
1318
|
storage: storageName,
|
|
1261
|
-
msg: verb + ` "` + prepared.name + `" to serve a getWhere query on "` +
|
|
1319
|
+
msg: verb + ` "` + prepared.name + `" to serve a getWhere query on "` + tableName + `". Writes to the table are paused until it completes. ` + slowOnLargeDatabaseNotice
|
|
1262
1320
|
});
|
|
1263
1321
|
let timeRef = Performance.now();
|
|
1264
1322
|
let entry = await runAndVerify(sql, prepared);
|
|
@@ -1270,15 +1328,15 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1270
1328
|
}), async exn => {
|
|
1271
1329
|
Logging.warn({
|
|
1272
1330
|
storage: storageName,
|
|
1273
|
-
msg: `Failed to create an index on "` +
|
|
1331
|
+
msg: `Failed to create an index on "` + tableName + `"("` + column + `") for a getWhere query. The query runs without it.`,
|
|
1274
1332
|
err: Utils.prettifyExn(exn)
|
|
1275
1333
|
});
|
|
1276
1334
|
return await resyncIndex(IndexDefinition.name(definition));
|
|
1277
1335
|
});
|
|
1278
1336
|
}));
|
|
1279
1337
|
};
|
|
1280
|
-
let ensureSchemaIndexes = async entities => {
|
|
1281
|
-
let schemaIndexes = getSchemaIndexes(entities.filter(e => e.storage.postgres));
|
|
1338
|
+
let ensureSchemaIndexes = async (entities, chainIds) => {
|
|
1339
|
+
let schemaIndexes = getSchemaIndexes(entities.filter(e => e.storage.postgres), partitionChainIds(chainIds));
|
|
1282
1340
|
await Promise.all(schemaIndexes.map(definition => Stdlib_Promise.$$catch(IndexManager.ensure(indexManager, definition, "Exact", async () => {
|
|
1283
1341
|
let prepared = IndexManager.prepare(indexManager, definition, "Exact", pgSchema);
|
|
1284
1342
|
if (prepared === undefined) {
|
|
@@ -1306,7 +1364,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1306
1364
|
})));
|
|
1307
1365
|
};
|
|
1308
1366
|
let finalizeBackfill = async (entities, chainIds, readyAt) => {
|
|
1309
|
-
let schemaIndexes = getSchemaIndexes(entities.filter(e => e.storage.postgres));
|
|
1367
|
+
let schemaIndexes = getSchemaIndexes(entities.filter(e => e.storage.postgres), partitionChainIds(chainIds));
|
|
1310
1368
|
let missing = Stdlib_Array.filterMap(schemaIndexes, definition => IndexManager.prepare(indexManager, definition, "Exact", pgSchema));
|
|
1311
1369
|
let rebuilt = missing.filter(prepared => prepared.isRebuild);
|
|
1312
1370
|
if (rebuilt.length !== 0) {
|
|
@@ -1362,9 +1420,6 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1362
1420
|
let setEffectCacheOrThrow = async (table, itemSchema, items, initialize) => {
|
|
1363
1421
|
if (initialize) {
|
|
1364
1422
|
await sql.unsafe(makeCreateTableQuery(table, pgSchema, false, undefined, undefined));
|
|
1365
|
-
if (onNewTables !== undefined) {
|
|
1366
|
-
await onNewTables([table.tableName]);
|
|
1367
|
-
}
|
|
1368
1423
|
}
|
|
1369
1424
|
return await setOrThrow$1(items, table, itemSchema);
|
|
1370
1425
|
};
|
|
@@ -1415,22 +1470,31 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1415
1470
|
return Logging.errorWithExn(Utils.prettifyExn(exn$1), `Failed to dump cache.`);
|
|
1416
1471
|
}
|
|
1417
1472
|
};
|
|
1418
|
-
let resumeInitialState = async (entities, throwIfIncompatible) => {
|
|
1473
|
+
let resumeInitialState = async (entities, chainIds, throwIfIncompatible) => {
|
|
1419
1474
|
let match = await Promise.all([
|
|
1420
1475
|
restoreEffectCache(false),
|
|
1421
|
-
InternalTable.Chains.getInitialState(sql, pgSchema).then(rawInitialStates =>
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1476
|
+
InternalTable.Chains.getInitialState(sql, pgSchema).then(rawInitialStates => {
|
|
1477
|
+
let rawInitialStates$1 = rawInitialStates.filter(rawInitialState => chainIds.includes(rawInitialState.id));
|
|
1478
|
+
return [
|
|
1479
|
+
rawInitialStates$1.map(rawInitialState => ({
|
|
1480
|
+
id: rawInitialState.id,
|
|
1481
|
+
startBlock: rawInitialState.startBlock,
|
|
1482
|
+
endBlock: Primitive_option.fromNull(rawInitialState.endBlock),
|
|
1483
|
+
maxReorgDepth: rawInitialState.maxReorgDepth,
|
|
1484
|
+
progressBlockNumber: rawInitialState.progressBlockNumber,
|
|
1485
|
+
progressBlockTime: InternalTable.Chains.blockTimeFromDb(rawInitialState.progressBlockTime),
|
|
1486
|
+
numEventsProcessed: rawInitialState.numEventsProcessed,
|
|
1487
|
+
firstEventBlockNumber: Primitive_option.fromNull(rawInitialState.firstEventBlockNumber),
|
|
1488
|
+
timestampCaughtUpToHeadOrEndblock: Primitive_option.fromNull(rawInitialState.timestampCaughtUpToHeadOrEndblock),
|
|
1489
|
+
addressRows: rawInitialState.addressRows,
|
|
1490
|
+
sourceBlockNumber: rawInitialState.sourceBlockNumber
|
|
1491
|
+
})),
|
|
1492
|
+
Frontier.fromEntries(rawInitialStates$1.map(rawInitialState => [
|
|
1493
|
+
rawInitialState.id,
|
|
1494
|
+
BigInt(rawInitialState.checkpointId)
|
|
1495
|
+
]))
|
|
1496
|
+
];
|
|
1497
|
+
}),
|
|
1434
1498
|
sql.unsafe(InternalTable.Checkpoints.makeGetReorgCheckpointsQuery(pgSchema)),
|
|
1435
1499
|
Promise.all([
|
|
1436
1500
|
InternalTable.EnvioInfo.read(sql, pgSchema),
|
|
@@ -1451,21 +1515,22 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1451
1515
|
}
|
|
1452
1516
|
})
|
|
1453
1517
|
]);
|
|
1454
|
-
let match$1 = match[
|
|
1518
|
+
let match$1 = match[3];
|
|
1455
1519
|
let storedContractMapping = match$1[1];
|
|
1456
1520
|
let storedEnvioInfo = match$1[0];
|
|
1457
|
-
let
|
|
1521
|
+
let match$2 = match[1];
|
|
1522
|
+
let checkpointFrontier = match$2[1];
|
|
1523
|
+
let chains = match$2[0];
|
|
1458
1524
|
throwIfIncompatible(storedEnvioInfo, storedContractMapping);
|
|
1459
1525
|
await reloadIndexCatalog();
|
|
1460
|
-
let
|
|
1461
|
-
let reorgCheckpoints = match[3].map(raw => ({
|
|
1526
|
+
let reorgCheckpoints = match[2].map(raw => ({
|
|
1462
1527
|
id: BigInt(raw.id),
|
|
1463
1528
|
chain_id: ChainId.normalizeOrThrow(raw.chain_id),
|
|
1464
1529
|
block_number: raw.block_number,
|
|
1465
1530
|
block_hash: raw.block_hash
|
|
1466
1531
|
}));
|
|
1467
1532
|
if (sink !== undefined) {
|
|
1468
|
-
await sink.resume(
|
|
1533
|
+
await sink.resume(checkpointFrontier, chains, entities);
|
|
1469
1534
|
}
|
|
1470
1535
|
return {
|
|
1471
1536
|
cleanRun: false,
|
|
@@ -1473,7 +1538,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1473
1538
|
envioInfo: storedEnvioInfo,
|
|
1474
1539
|
cache: match[0],
|
|
1475
1540
|
chains: chains,
|
|
1476
|
-
|
|
1541
|
+
checkpointFrontier: checkpointFrontier,
|
|
1477
1542
|
reorgCheckpoints: reorgCheckpoints
|
|
1478
1543
|
};
|
|
1479
1544
|
};
|
|
@@ -1487,7 +1552,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1487
1552
|
let getRollbackTargetCheckpoint = (reorgChainId, lastKnownValidBlockNumber) => InternalTable.Checkpoints.getRollbackTargetCheckpoint(sql, pgSchema, reorgChainId, lastKnownValidBlockNumber);
|
|
1488
1553
|
let getRollbackProgressDiff = floors => InternalTable.Checkpoints.getRollbackProgressDiff(sql, pgSchema, floors);
|
|
1489
1554
|
let getRollbackData = async (entityConfig, floors) => {
|
|
1490
|
-
let params =
|
|
1555
|
+
let params = CheckpointSequence.params(floors.checkpointBounds);
|
|
1491
1556
|
let match = await Promise.all([
|
|
1492
1557
|
sql.unsafe(makeGetRollbackRemovedIdsQuery(entityConfig, pgSchema, floors), params, {prepare: true}),
|
|
1493
1558
|
sql.unsafe(makeGetRollbackPreTargetRowsQuery(entityConfig, pgSchema, floors), params, {prepare: true})
|
|
@@ -1521,7 +1586,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1521
1586
|
S$RescriptSchema.parseOrThrow(restoredEntitiesResult, Table.pgRowsSchema(entityConfig.table))
|
|
1522
1587
|
];
|
|
1523
1588
|
};
|
|
1524
|
-
let writeBatchMethod = async (batch, rollback,
|
|
1589
|
+
let writeBatchMethod = async (batch, rollback, config, allEntities, updatedEffectsCache, updatedEntities, registeredAddresses, chainMetaData, onWrite) => {
|
|
1525
1590
|
let pgUpdates = [];
|
|
1526
1591
|
let chUpdates = [];
|
|
1527
1592
|
for (let i = 0, i_finish = updatedEntities.length; i < i_finish; ++i) {
|
|
@@ -1537,14 +1602,14 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1537
1602
|
let sinkPromise;
|
|
1538
1603
|
if (sink !== undefined) {
|
|
1539
1604
|
let timerRef = Performance.now();
|
|
1540
|
-
sinkPromise = sink.writeBatch(batch, chUpdates).then(() => {
|
|
1605
|
+
sinkPromise = sink.writeBatch(batch, rollback !== undefined ? rollback.diffCheckpoints : [], chUpdates).then(() => {
|
|
1541
1606
|
onWrite(sink.name, Performance.secondsSince(timerRef));
|
|
1542
1607
|
}).catch(exn => exn);
|
|
1543
1608
|
} else {
|
|
1544
1609
|
sinkPromise = undefined;
|
|
1545
1610
|
}
|
|
1546
1611
|
let primaryTimerRef = Performance.now();
|
|
1547
|
-
await writeBatch(sql, batch, pgSchema, rollback,
|
|
1612
|
+
await writeBatch(sql, batch, pgSchema, rollback, config, allEntities, setEffectCacheOrThrow, setQueryCache, updatedEffectsCache, pgUpdates, registeredAddresses, sinkPromise, chainMetaData, undefined);
|
|
1548
1613
|
return onWrite(storageName, Performance.secondsSince(primaryTimerRef));
|
|
1549
1614
|
};
|
|
1550
1615
|
let close = () => sql.end();
|
|
@@ -1596,21 +1661,14 @@ function makeStorageFromEnv(config, sqlOpt, pgSchemaOpt, isHasuraEnabledOpt) {
|
|
|
1596
1661
|
if (missing.length !== 0) {
|
|
1597
1662
|
Stdlib_JsError.throwWithMessage(`ClickHouse storage is enabled but required env vars are not set: ` + missing.join(", ") + `. Please set them, disable clickhouse in the \`storage\` config, or run \`envio dev\` for a pre-configured local ClickHouse.`);
|
|
1598
1663
|
}
|
|
1599
|
-
tmp = Sink.makeClickHouse(host, database, username, password, config.chainIdMode);
|
|
1664
|
+
tmp = Sink.makeClickHouse(host, database, username, password, config.checkpointSequence, config.chainIdMode);
|
|
1600
1665
|
} else {
|
|
1601
1666
|
tmp = undefined;
|
|
1602
1667
|
}
|
|
1603
|
-
return make(sql, Env.Db.host, pgSchema, Env.Db.port, Env.Db.user, Env.Db.database, Env.Db.password, isHasuraEnabled, config.chainIdMode, config.ecosystem.name, tmp, isHasuraEnabled ? () => Stdlib_Promise.$$catch(Hasura.trackDatabase(Env.Hasura.graphqlEndpoint, {
|
|
1668
|
+
return make(sql, Env.Db.host, pgSchema, Env.Db.port, Env.Db.user, Env.Db.database, Env.Db.password, isHasuraEnabled, config.chainIdMode, config.ecosystem.name, tmp, config.isolated, isHasuraEnabled ? () => Stdlib_Promise.$$catch(Hasura.trackDatabase(Env.Hasura.graphqlEndpoint, {
|
|
1604
1669
|
role: Env.Hasura.role,
|
|
1605
1670
|
secret: Env.Hasura.secret
|
|
1606
|
-
}, pgSchema, Config.getPgUserEntities(config), Env.Hasura.aggregateEntities, Env.Hasura.responseLimit, Schema.make(config.userEntities.map(e => e.table))), err => Promise.resolve(Logging.errorWithExn(Utils.prettifyExn(err), `Error tracking tables`))) : undefined
|
|
1607
|
-
role: Env.Hasura.role,
|
|
1608
|
-
secret: Env.Hasura.secret
|
|
1609
|
-
}, pgSchema, tableNames.map(tableName => ({
|
|
1610
|
-
tableName: tableName,
|
|
1611
|
-
description: undefined,
|
|
1612
|
-
columnConfigs: {}
|
|
1613
|
-
}))), err => Promise.resolve(Logging.errorWithExn(Utils.prettifyExn(err), `Error tracking new tables`))) : undefined);
|
|
1671
|
+
}, pgSchema, Config.getPgUserEntities(config), Env.Hasura.aggregateEntities, Env.Hasura.responseLimit, Schema.make(config.userEntities.map(e => e.table))), err => Promise.resolve(Logging.errorWithExn(Utils.prettifyExn(err), `Error tracking tables`))) : undefined);
|
|
1614
1672
|
}
|
|
1615
1673
|
|
|
1616
1674
|
function makePersistenceFromConfig(config, storageOpt) {
|
|
@@ -1624,9 +1682,10 @@ export {
|
|
|
1624
1682
|
makeClient,
|
|
1625
1683
|
formatSeconds,
|
|
1626
1684
|
slowOnLargeDatabaseNotice,
|
|
1685
|
+
partitionTableName,
|
|
1686
|
+
indexTableNames,
|
|
1627
1687
|
getSchemaIndexes,
|
|
1628
1688
|
makeCreateTableQuery,
|
|
1629
|
-
partitionTableName,
|
|
1630
1689
|
rowSchemaCache,
|
|
1631
1690
|
getRowSchema,
|
|
1632
1691
|
entityHistoryCache,
|
|
@@ -1658,6 +1717,7 @@ export {
|
|
|
1658
1717
|
deleteByIdsOrThrow,
|
|
1659
1718
|
makeInsertDeleteUpdatesQuery,
|
|
1660
1719
|
executeSet,
|
|
1720
|
+
pickCheckpoints,
|
|
1661
1721
|
writeBatch,
|
|
1662
1722
|
rollbackKeyColumns,
|
|
1663
1723
|
makeGetRollbackPreTargetRowsQuery,
|
|
@@ -12,7 +12,7 @@ let maxEntitiesPerWrite = 5
|
|
|
12
12
|
let forcedIntervalMultiplier = 5.
|
|
13
13
|
|
|
14
14
|
type targets = {
|
|
15
|
-
safeCheckpoints:
|
|
15
|
+
safeCheckpoints: CheckpointSequence.checkpointBoundsByChain,
|
|
16
16
|
concurrent: array<Internal.entityConfig>,
|
|
17
17
|
forced: array<Internal.entityConfig>,
|
|
18
18
|
}
|
|
@@ -28,25 +28,19 @@ type targets = {
|
|
|
28
28
|
// every chain back to one checkpoint, which can sit below another chain's safe
|
|
29
29
|
// point, so the lowest is the only bound every chain agrees on.
|
|
30
30
|
let selectSafeCheckpoints = (state: IndexerState.t) => {
|
|
31
|
+
let sequence = (state->IndexerState.config).checkpointSequence
|
|
31
32
|
let byChain = state->IndexerState.getSafeCheckpointIdByChain
|
|
32
33
|
let safe =
|
|
33
34
|
byChain->Array.filterMap(((chainId, checkpointId)) =>
|
|
34
35
|
checkpointId->Option.map(checkpointId => (chainId, checkpointId))
|
|
35
36
|
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
CheckpointBounds.EveryChain(
|
|
42
|
-
safe->Array.reduce(lowest, (lowest, (_, checkpointId)) =>
|
|
43
|
-
Pervasives.min(lowest, checkpointId)
|
|
44
|
-
),
|
|
45
|
-
),
|
|
46
|
-
)
|
|
47
|
-
} else {
|
|
48
|
-
None
|
|
37
|
+
// Under one shared sequence the bound is the lowest of them, which only
|
|
38
|
+
// exists once every chain has one.
|
|
39
|
+
let hasBound = switch sequence {
|
|
40
|
+
| PerChain => safe->Utils.Array.notEmpty
|
|
41
|
+
| SharedAcrossChains => safe->Array.length === byChain->Array.length
|
|
49
42
|
}
|
|
43
|
+
hasBound ? Some({CheckpointSequence.sequence, byChain: Frontier.fromEntries(safe)}) : None
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
let selectFrom = (
|
|
@@ -103,7 +97,7 @@ let selectFrom = (
|
|
|
103
97
|
|
|
104
98
|
let select = (state: IndexerState.t, ~writtenEntityNames, ~isRollback) => {
|
|
105
99
|
let config = state->IndexerState.config
|
|
106
|
-
if config->
|
|
100
|
+
if config->HistoryPolicy.mayPrune(~shouldSaveHistory=state->IndexerState.shouldSaveHistory) {
|
|
107
101
|
state
|
|
108
102
|
->selectSafeCheckpoints
|
|
109
103
|
->Option.map(safeCheckpoints =>
|
|
@@ -3,16 +3,17 @@
|
|
|
3
3
|
import * as Env from "./Env.res.mjs";
|
|
4
4
|
import * as Table from "./db/Table.res.mjs";
|
|
5
5
|
import * as Utils from "./Utils.res.mjs";
|
|
6
|
-
import * as Config from "./Config.res.mjs";
|
|
7
6
|
import * as Logging from "./Logging.res.mjs";
|
|
7
|
+
import * as Frontier from "./db/Frontier.res.mjs";
|
|
8
8
|
import * as Performance from "./bindings/Performance.res.mjs";
|
|
9
9
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
10
10
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
11
|
+
import * as HistoryPolicy from "./HistoryPolicy.res.mjs";
|
|
11
12
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
12
|
-
import * as Primitive_bigint from "@rescript/runtime/lib/es6/Primitive_bigint.js";
|
|
13
13
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
14
14
|
|
|
15
15
|
function selectSafeCheckpoints(state) {
|
|
16
|
+
let sequence = IndexerState.config(state).checkpointSequence;
|
|
16
17
|
let byChain = IndexerState.getSafeCheckpointIdByChain(state);
|
|
17
18
|
let safe = Stdlib_Array.filterMap(byChain, param => {
|
|
18
19
|
let chainId = param[0];
|
|
@@ -21,24 +22,14 @@ function selectSafeCheckpoints(state) {
|
|
|
21
22
|
checkpointId
|
|
22
23
|
]);
|
|
23
24
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
25
|
+
let hasBound;
|
|
26
|
+
hasBound = sequence === "SharedAcrossChains" ? safe.length === byChain.length : Utils.$$Array.notEmpty(safe);
|
|
27
|
+
if (hasBound) {
|
|
28
|
+
return {
|
|
29
|
+
sequence: sequence,
|
|
30
|
+
byChain: Frontier.fromEntries(safe)
|
|
31
|
+
};
|
|
33
32
|
}
|
|
34
|
-
if (safe.length !== byChain.length) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
let match = safe[0];
|
|
38
|
-
return {
|
|
39
|
-
TAG: "EveryChain",
|
|
40
|
-
_0: Stdlib_Array.reduce(safe, match[1], (lowest, param) => Primitive_bigint.min(lowest, param[1]))
|
|
41
|
-
};
|
|
42
33
|
}
|
|
43
34
|
|
|
44
35
|
function selectFrom(allEntities, lastPrunedAtMillis, writtenEntityNames, isRollback, nowMillis, intervalMillis, safeCheckpoints) {
|
|
@@ -83,7 +74,7 @@ function selectFrom(allEntities, lastPrunedAtMillis, writtenEntityNames, isRollb
|
|
|
83
74
|
|
|
84
75
|
function select(state, writtenEntityNames, isRollback) {
|
|
85
76
|
let config = IndexerState.config(state);
|
|
86
|
-
if (
|
|
77
|
+
if (HistoryPolicy.mayPrune(config, IndexerState.shouldSaveHistory(state))) {
|
|
87
78
|
return Stdlib_Option.map(selectSafeCheckpoints(state), safeCheckpoints => selectFrom(IndexerState.persistence(state).allEntities, IndexerState.lastPrunedAtMillis(state), writtenEntityNames, isRollback, Date.now(), Env.ThrottleWrites.pruneStaleDataIntervalMillis, safeCheckpoints));
|
|
88
79
|
}
|
|
89
80
|
}
|
package/src/Rollback.res
CHANGED
|
@@ -132,19 +132,14 @@ and executeRollback = async (
|
|
|
132
132
|
// flush above leaves a diff pending only when no batch has come along to
|
|
133
133
|
// carry it.
|
|
134
134
|
let floors = {
|
|
135
|
-
let
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
~floorCheckpointId=rollbackTargetCheckpointId,
|
|
144
|
-
~reorgChainId=reorgChain,
|
|
145
|
-
~forkBlockNumber=rollbackTargetBlockNumber,
|
|
146
|
-
)
|
|
147
|
-
}
|
|
135
|
+
let config = state->IndexerState.config
|
|
136
|
+
let next = RollbackFloors.make(
|
|
137
|
+
~sequence=config.checkpointSequence,
|
|
138
|
+
~chainIds=config.chainMap->ChainMap.keys,
|
|
139
|
+
~reorgChainId=reorgChain,
|
|
140
|
+
~floorCheckpointId=rollbackTargetCheckpointId,
|
|
141
|
+
~forkBlockNumber=rollbackTargetBlockNumber,
|
|
142
|
+
)
|
|
148
143
|
switch state->IndexerState.pendingRollback {
|
|
149
144
|
| None => next
|
|
150
145
|
| Some({floors: pending}) => RollbackFloors.merge(pending, next)
|
|
@@ -205,6 +200,7 @@ and executeRollback = async (
|
|
|
205
200
|
->Array.push({
|
|
206
201
|
chainId,
|
|
207
202
|
progressBlockNumber: toBlock,
|
|
203
|
+
progressBlockTime: cs->ChainState.committedProgressBlockTime,
|
|
208
204
|
sourceBlockNumber: cs->ChainState.knownHeight,
|
|
209
205
|
totalEventsProcessed: cs->ChainState.numEventsProcessed,
|
|
210
206
|
})
|
|
@@ -221,7 +217,6 @@ and executeRollback = async (
|
|
|
221
217
|
|
|
222
218
|
let diff = await state->InMemoryStore.prepareRollbackDiff(
|
|
223
219
|
~floors,
|
|
224
|
-
~rollbackDiffCheckpointId=state->IndexerState.committedCheckpointId->BigInt.add(1n),
|
|
225
220
|
~progressedChains=rolledBackChains,
|
|
226
221
|
~rolledBackAddresses,
|
|
227
222
|
)
|