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.
Files changed (89) hide show
  1. package/index.d.ts +3 -0
  2. package/package.json +6 -6
  3. package/src/Batch.res +111 -78
  4. package/src/Batch.res.mjs +53 -46
  5. package/src/BatchProcessing.res +1 -11
  6. package/src/BatchProcessing.res.mjs +1 -4
  7. package/src/ChainState.res +72 -19
  8. package/src/ChainState.res.mjs +50 -12
  9. package/src/ChainState.resi +5 -0
  10. package/src/Config.res +58 -37
  11. package/src/Config.res.mjs +63 -53
  12. package/src/CrossChainState.res +49 -52
  13. package/src/CrossChainState.res.mjs +25 -23
  14. package/src/CrossChainState.resi +6 -13
  15. package/src/EffectState.res +13 -4
  16. package/src/EffectState.resi +7 -1
  17. package/src/EventProcessing.res +6 -6
  18. package/src/EventProcessing.res.mjs +6 -6
  19. package/src/FetchState.res +14 -0
  20. package/src/FetchState.res.mjs +14 -0
  21. package/src/FinalizeBackfill.res +16 -12
  22. package/src/FinalizeBackfill.res.mjs +3 -3
  23. package/src/HistoryPolicy.res +46 -0
  24. package/src/HistoryPolicy.res.mjs +50 -0
  25. package/src/InMemoryStore.res +30 -32
  26. package/src/InMemoryStore.res.mjs +33 -28
  27. package/src/IndexerState.res +66 -45
  28. package/src/IndexerState.res.mjs +57 -29
  29. package/src/IndexerState.resi +8 -13
  30. package/src/Internal.res +4 -2
  31. package/src/LoadLayer.res +11 -4
  32. package/src/LoadLayer.res.mjs +8 -5
  33. package/src/Main.res +25 -24
  34. package/src/Main.res.mjs +24 -25
  35. package/src/Metrics.res +49 -1
  36. package/src/Metrics.res.mjs +26 -3
  37. package/src/Persistence.res +55 -16
  38. package/src/Persistence.res.mjs +18 -3
  39. package/src/PgStorage.res +194 -118
  40. package/src/PgStorage.res.mjs +132 -72
  41. package/src/PruneStaleHistory.res +9 -15
  42. package/src/PruneStaleHistory.res.mjs +11 -20
  43. package/src/Rollback.res +9 -14
  44. package/src/Rollback.res.mjs +5 -3
  45. package/src/Sink.res +7 -5
  46. package/src/Sink.res.mjs +4 -4
  47. package/src/Staging.res +298 -0
  48. package/src/Staging.res.mjs +257 -0
  49. package/src/TestIndexer.res +5 -5
  50. package/src/TestIndexer.res.mjs +7 -6
  51. package/src/UserContext.res +7 -4
  52. package/src/UserContext.res.mjs +5 -2
  53. package/src/Utils.res +9 -0
  54. package/src/Utils.res.mjs +9 -0
  55. package/src/Writing.res +34 -20
  56. package/src/Writing.res.mjs +15 -20
  57. package/src/bindings/ClickHouse.res +41 -34
  58. package/src/bindings/ClickHouse.res.mjs +36 -30
  59. package/src/bindings/ClickHouseSink.res +45 -186
  60. package/src/bindings/ClickHouseSink.res.mjs +21 -174
  61. package/src/db/CheckpointSequence.res +109 -0
  62. package/src/db/CheckpointSequence.res.mjs +99 -0
  63. package/src/db/EntityHistory.res +6 -5
  64. package/src/db/EntityHistory.res.mjs +5 -5
  65. package/src/db/Frontier.res +86 -0
  66. package/src/db/Frontier.res.mjs +126 -0
  67. package/src/db/InternalTable.res +145 -27
  68. package/src/db/InternalTable.res.mjs +115 -29
  69. package/src/db/RollbackFloors.res +34 -41
  70. package/src/db/RollbackFloors.res.mjs +27 -71
  71. package/src/sources/BlockStore.res +3 -0
  72. package/src/sources/EvmHyperSyncSource.res +3 -1
  73. package/src/sources/EvmHyperSyncSource.res.mjs +2 -1
  74. package/src/sources/HyperSync.res +2 -0
  75. package/src/sources/HyperSync.res.mjs +1 -0
  76. package/src/sources/HyperSync.resi +1 -0
  77. package/src/sources/HyperSyncClient.res +3 -0
  78. package/src/sources/RequestStat.res +8 -1
  79. package/src/sources/Source.res +4 -3
  80. package/src/sources/SourceManager.res +30 -10
  81. package/src/sources/SourceManager.res.mjs +24 -7
  82. package/src/sources/SourceManager.resi +2 -0
  83. package/src/tui/Tui.res +56 -143
  84. package/src/tui/Tui.res.mjs +70 -166
  85. package/src/tui/components/TuiData.res +61 -16
  86. package/src/tui/components/TuiData.res.mjs +53 -15
  87. package/svm.schema.json +0 -7
  88. package/src/db/CheckpointBounds.res +0 -53
  89. package/src/db/CheckpointBounds.res.mjs +0 -44
@@ -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 getSchemaIndexes(entities) {
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.table,
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
- async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, setQueryCache, updatedEffectsCache, updatedEntities, registeredAddresses, sinkPromise, chainMetaData, escapeTables) {
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 shouldSaveHistory = Config.shouldSaveHistory(config, isInReorgThreshold, undefined);
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.map(rollback, r => r.diffCheckpointId);
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 (shouldSaveHistory) {
887
- setOperations.push(sql => InternalTable.Checkpoints.insert(sql, pgSchema, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointBlockHashes, batch.checkpointEventsProcessed, chainIdMode));
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, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, setQueryCache, updatedEffectsCache, updatedEntities, registeredAddresses, sinkPromise, chainMetaData, Primitive_option.some(escapeTables$1));
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 = CheckpointBounds.sql(floors.floors, Table.getPgChainIdColumn(entityConfig.table), tableRef);
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 = CheckpointBounds.sql(floors.floors, Table.getPgChainIdColumn(entityConfig.table), tableRef);
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, onInitialize, onNewTables) {
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
- checkpointId: InternalTable.Checkpoints.initialCheckpointId,
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 ensureQueryIndexes = async (table, filters) => {
1250
- let columns = filterColumns(table, filters);
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(table.tableName, column);
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 "` + table.tableName + `". Writes to the table are paused until it completes. ` + slowOnLargeDatabaseNotice
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 "` + table.tableName + `"("` + column + `") for a getWhere query. The query runs without it.`,
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 => rawInitialStates.map(rawInitialState => ({
1422
- id: rawInitialState.id,
1423
- startBlock: rawInitialState.startBlock,
1424
- endBlock: Primitive_option.fromNull(rawInitialState.endBlock),
1425
- maxReorgDepth: rawInitialState.maxReorgDepth,
1426
- progressBlockNumber: rawInitialState.progressBlockNumber,
1427
- numEventsProcessed: rawInitialState.numEventsProcessed,
1428
- firstEventBlockNumber: Primitive_option.fromNull(rawInitialState.firstEventBlockNumber),
1429
- timestampCaughtUpToHeadOrEndblock: Primitive_option.fromNull(rawInitialState.timestampCaughtUpToHeadOrEndblock),
1430
- addressRows: rawInitialState.addressRows,
1431
- sourceBlockNumber: rawInitialState.sourceBlockNumber
1432
- }))),
1433
- sql.unsafe(InternalTable.Checkpoints.makeCommitedCheckpointIdQuery(pgSchema)),
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[4];
1518
+ let match$1 = match[3];
1455
1519
  let storedContractMapping = match$1[1];
1456
1520
  let storedEnvioInfo = match$1[0];
1457
- let chains = match[1];
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 checkpointId = BigInt(match[2][0].id);
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(checkpointId, chains, entities);
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
- checkpointId: checkpointId,
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 = CheckpointBounds.params(floors.floors);
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, isInReorgThreshold, config, allEntities, updatedEffectsCache, updatedEntities, registeredAddresses, chainMetaData, onWrite) => {
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, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, setQueryCache, updatedEffectsCache, pgUpdates, registeredAddresses, sinkPromise, chainMetaData, undefined);
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, isHasuraEnabled ? tableNames => Stdlib_Promise.$$catch(Hasura.trackTables(Env.Hasura.graphqlEndpoint, {
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: CheckpointBounds.t,
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
- if state->IndexerState.config->Config.isIsolatedMultichain {
37
- safe->Utils.Array.notEmpty ? Some(CheckpointBounds.PerChain(safe)) : None
38
- } else if safe->Array.length === byChain->Array.length {
39
- let (_, lowest) = safe->Array.getUnsafe(0)
40
- Some(
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->Config.shouldPruneHistory(~isInReorgThreshold=state->IndexerState.isInReorgThreshold) {
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
- if (Config.isIsolatedMultichain(IndexerState.config(state))) {
25
- if (Utils.$$Array.notEmpty(safe)) {
26
- return {
27
- TAG: "PerChain",
28
- _0: safe
29
- };
30
- } else {
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 (Config.shouldPruneHistory(config, IndexerState.isInReorgThreshold(state))) {
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 next = if state->IndexerState.config->Config.isIsolatedMultichain {
136
- RollbackFloors.isolated(
137
- ~chainId=reorgChain,
138
- ~floorCheckpointId=rollbackTargetCheckpointId,
139
- ~forkBlockNumber=rollbackTargetBlockNumber,
140
- )
141
- } else {
142
- RollbackFloors.global(
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
  )