envio 3.1.1 → 3.2.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/evm.schema.json +83 -11
- package/fuel.schema.json +83 -11
- package/index.d.ts +184 -3
- package/package.json +6 -6
- package/src/Batch.res +2 -2
- package/src/ChainFetcher.res +27 -3
- package/src/ChainFetcher.res.mjs +17 -3
- package/src/ChainManager.res +163 -0
- package/src/ChainManager.res.mjs +136 -0
- package/src/Config.res +213 -30
- package/src/Config.res.mjs +102 -41
- package/src/Core.res +16 -10
- package/src/Ecosystem.res +0 -3
- package/src/Env.res +2 -2
- package/src/Env.res.mjs +2 -2
- package/src/Envio.res +101 -2
- package/src/Envio.res.mjs +2 -3
- package/src/EventConfigBuilder.res +52 -0
- package/src/EventConfigBuilder.res.mjs +32 -0
- package/src/EventUtils.res +2 -2
- package/src/FetchState.res +126 -71
- package/src/FetchState.res.mjs +73 -51
- package/src/GlobalState.res +219 -363
- package/src/GlobalState.res.mjs +314 -491
- package/src/GlobalStateManager.res +49 -59
- package/src/GlobalStateManager.res.mjs +5 -4
- package/src/GlobalStateManager.resi +1 -1
- package/src/HandlerLoader.res +12 -1
- package/src/HandlerLoader.res.mjs +6 -1
- package/src/HandlerRegister.res +9 -9
- package/src/HandlerRegister.res.mjs +9 -9
- package/src/Hasura.res +102 -32
- package/src/Hasura.res.mjs +88 -34
- package/src/InMemoryStore.res +10 -1
- package/src/InMemoryStore.res.mjs +4 -1
- package/src/InMemoryTable.res +83 -136
- package/src/InMemoryTable.res.mjs +57 -86
- package/src/Internal.res +54 -5
- package/src/Internal.res.mjs +2 -8
- package/src/LazyLoader.res +2 -2
- package/src/LazyLoader.res.mjs +3 -3
- package/src/LoadLayer.res +47 -60
- package/src/LoadLayer.res.mjs +28 -50
- package/src/LoadLayer.resi +2 -5
- package/src/LogSelection.res +4 -4
- package/src/LogSelection.res.mjs +5 -7
- package/src/Logging.res +1 -1
- package/src/Main.res +61 -2
- package/src/Main.res.mjs +37 -1
- package/src/Persistence.res +3 -16
- package/src/PgStorage.res +125 -114
- package/src/PgStorage.res.mjs +112 -95
- package/src/Ports.res +5 -0
- package/src/Ports.res.mjs +9 -0
- package/src/Prometheus.res +3 -3
- package/src/Prometheus.res.mjs +4 -4
- package/src/ReorgDetection.res +4 -4
- package/src/ReorgDetection.res.mjs +4 -5
- package/src/SafeCheckpointTracking.res +16 -16
- package/src/SafeCheckpointTracking.res.mjs +2 -2
- package/src/SimulateItems.res +10 -14
- package/src/SimulateItems.res.mjs +5 -2
- package/src/Sink.res +1 -1
- package/src/Sink.res.mjs +1 -2
- package/src/SvmTypes.res +9 -0
- package/src/SvmTypes.res.mjs +14 -0
- package/src/TestIndexer.res +17 -57
- package/src/TestIndexer.res.mjs +14 -48
- package/src/TestIndexerProxyStorage.res +23 -23
- package/src/TestIndexerProxyStorage.res.mjs +12 -15
- package/src/Throttler.res +2 -2
- package/src/Time.res +2 -2
- package/src/Time.res.mjs +2 -2
- package/src/UserContext.res +19 -118
- package/src/UserContext.res.mjs +10 -66
- package/src/Utils.res +15 -15
- package/src/Utils.res.mjs +7 -8
- package/src/adapters/MarkBatchProcessedAdapter.res +5 -0
- package/src/adapters/MarkBatchProcessedAdapter.res.mjs +14 -0
- package/src/bindings/BigDecimal.res +1 -1
- package/src/bindings/BigDecimal.res.mjs +2 -2
- package/src/bindings/ClickHouse.res +8 -6
- package/src/bindings/ClickHouse.res.mjs +5 -5
- package/src/bindings/Hrtime.res +1 -1
- package/src/bindings/Pino.res +2 -2
- package/src/bindings/Pino.res.mjs +3 -4
- package/src/db/EntityFilter.res +410 -0
- package/src/db/EntityFilter.res.mjs +424 -0
- package/src/db/EntityHistory.res +1 -1
- package/src/db/EntityHistory.res.mjs +1 -1
- package/src/db/InternalTable.res +10 -10
- package/src/db/InternalTable.res.mjs +41 -45
- package/src/db/Schema.res +2 -2
- package/src/db/Schema.res.mjs +3 -3
- package/src/db/Table.res +106 -22
- package/src/db/Table.res.mjs +84 -35
- package/src/sources/EventRouter.res +67 -2
- package/src/sources/EventRouter.res.mjs +45 -3
- package/src/sources/Evm.res +0 -7
- package/src/sources/Evm.res.mjs +0 -15
- package/src/sources/EvmChain.res +1 -1
- package/src/sources/EvmChain.res.mjs +1 -2
- package/src/sources/EvmRpcClient.res +42 -0
- package/src/sources/EvmRpcClient.res.mjs +64 -0
- package/src/sources/Fuel.res +0 -7
- package/src/sources/Fuel.res.mjs +0 -15
- package/src/sources/HyperFuelSource.res +5 -4
- package/src/sources/HyperFuelSource.res.mjs +2 -2
- package/src/sources/HyperSyncClient.res +9 -5
- package/src/sources/HyperSyncClient.res.mjs +2 -2
- package/src/sources/HyperSyncHeightStream.res +2 -2
- package/src/sources/HyperSyncHeightStream.res.mjs +2 -2
- package/src/sources/HyperSyncSource.res +10 -9
- package/src/sources/HyperSyncSource.res.mjs +4 -4
- package/src/sources/Rpc.res +1 -5
- package/src/sources/Rpc.res.mjs +1 -9
- package/src/sources/RpcSource.res +57 -21
- package/src/sources/RpcSource.res.mjs +47 -20
- package/src/sources/RpcWebSocketHeightStream.res +1 -1
- package/src/sources/SourceManager.res +3 -2
- package/src/sources/SourceManager.res.mjs +1 -1
- package/src/sources/Svm.res +3 -10
- package/src/sources/Svm.res.mjs +4 -18
- package/src/sources/SvmHyperSyncClient.res +265 -0
- package/src/sources/SvmHyperSyncClient.res.mjs +28 -0
- package/src/sources/SvmHyperSyncSource.res +638 -0
- package/src/sources/SvmHyperSyncSource.res.mjs +557 -0
- package/src/tui/Tui.res +9 -2
- package/src/tui/Tui.res.mjs +18 -3
- package/src/tui/components/BufferedProgressBar.res +2 -2
- package/src/tui/components/TuiData.res +3 -0
- package/svm.schema.json +523 -14
- package/src/TableIndices.res +0 -115
- package/src/TableIndices.res.mjs +0 -144
package/src/PgStorage.res.mjs
CHANGED
|
@@ -13,11 +13,11 @@ import * as Schema from "./db/Schema.res.mjs";
|
|
|
13
13
|
import * as Logging from "./Logging.res.mjs";
|
|
14
14
|
import * as Internal from "./Internal.res.mjs";
|
|
15
15
|
import Postgres from "postgres";
|
|
16
|
-
import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
|
|
17
16
|
import * as EventUtils from "./EventUtils.res.mjs";
|
|
18
17
|
import * as Prometheus from "./Prometheus.res.mjs";
|
|
19
18
|
import * as Persistence from "./Persistence.res.mjs";
|
|
20
19
|
import * as ChainFetcher from "./ChainFetcher.res.mjs";
|
|
20
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
21
21
|
import * as EntityHistory from "./db/EntityHistory.res.mjs";
|
|
22
22
|
import * as InternalTable from "./db/InternalTable.res.mjs";
|
|
23
23
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
@@ -49,7 +49,7 @@ function makeClient() {
|
|
|
49
49
|
|
|
50
50
|
function makeCreateIndexQuery(tableName, indexFields, pgSchema) {
|
|
51
51
|
let indexName = tableName + "_" + indexFields.join("_");
|
|
52
|
-
let index =
|
|
52
|
+
let index = indexFields.map(idx => `"` + idx + `"`).join(", ");
|
|
53
53
|
return `CREATE INDEX IF NOT EXISTS "` + indexName + `" ON "` + pgSchema + `"."` + tableName + `"(` + index + `);`;
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -71,7 +71,7 @@ function directionToIndexName(direction) {
|
|
|
71
71
|
|
|
72
72
|
function makeCreateCompositeIndexQuery(tableName, indexFields, pgSchema) {
|
|
73
73
|
let indexName = tableName + "_" + indexFields.map(f => f.fieldName + directionToIndexName(f.direction)).join("_");
|
|
74
|
-
let index =
|
|
74
|
+
let index = indexFields.map(f => `"` + f.fieldName + `"` + directionToSql(f.direction)).join(", ");
|
|
75
75
|
return `CREATE INDEX IF NOT EXISTS "` + indexName + `" ON "` + pgSchema + `"."` + tableName + `"(` + index + `);`;
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -88,14 +88,14 @@ function makeCreateTableQuery(table, pgSchema, isNumericArrayAsText) {
|
|
|
88
88
|
let fieldsMapped = Table.getFields(table).map(field => {
|
|
89
89
|
let defaultValue = field.defaultValue;
|
|
90
90
|
let isNullable = field.isNullable;
|
|
91
|
-
let fieldName = Table.
|
|
91
|
+
let fieldName = Table.getPgDbFieldName(field);
|
|
92
92
|
return `"` + fieldName + `" ` + Table.getPgFieldType(field.fieldType, pgSchema, field.isArray, isNumericArrayAsText, isNullable) + (
|
|
93
93
|
defaultValue !== undefined ? ` DEFAULT ` + defaultValue : (
|
|
94
94
|
isNullable ? `` : ` NOT NULL`
|
|
95
95
|
)
|
|
96
96
|
);
|
|
97
97
|
}).join(", ");
|
|
98
|
-
let primaryKeyFieldNames = Table.
|
|
98
|
+
let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table);
|
|
99
99
|
let primaryKey = primaryKeyFieldNames.map(field => `"` + field + `"`).join(", ");
|
|
100
100
|
return `CREATE TABLE IF NOT EXISTS "` + pgSchema + `"."` + table.tableName + `"(` + fieldsMapped + (
|
|
101
101
|
primaryKeyFieldNames.length !== 0 ? `, PRIMARY KEY(` + primaryKey + `)` : ""
|
|
@@ -109,7 +109,7 @@ function getEntityHistory(entityConfig) {
|
|
|
109
109
|
if (cache !== undefined) {
|
|
110
110
|
return cache;
|
|
111
111
|
}
|
|
112
|
-
let dataFields =
|
|
112
|
+
let dataFields = Stdlib_Array.filterMap(entityConfig.table.fields, field => {
|
|
113
113
|
if (field.TAG !== "Field") {
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
@@ -128,7 +128,9 @@ function getEntityHistory(entityConfig) {
|
|
|
128
128
|
isIndex: field$1.isIndex,
|
|
129
129
|
linkedEntity: field$1.linkedEntity,
|
|
130
130
|
defaultValue: field$1.defaultValue,
|
|
131
|
-
description: field$1.description
|
|
131
|
+
description: field$1.description,
|
|
132
|
+
postgresDbName: field$1.postgresDbName,
|
|
133
|
+
clickhouseDbName: field$1.clickhouseDbName
|
|
132
134
|
}
|
|
133
135
|
};
|
|
134
136
|
} else {
|
|
@@ -144,16 +146,18 @@ function getEntityHistory(entityConfig) {
|
|
|
144
146
|
isIndex: false,
|
|
145
147
|
linkedEntity: field$1.linkedEntity,
|
|
146
148
|
defaultValue: field$1.defaultValue,
|
|
147
|
-
description: field$1.description
|
|
149
|
+
description: field$1.description,
|
|
150
|
+
postgresDbName: field$1.postgresDbName,
|
|
151
|
+
clickhouseDbName: field$1.clickhouseDbName
|
|
148
152
|
}
|
|
149
153
|
};
|
|
150
154
|
}
|
|
151
155
|
});
|
|
152
|
-
let actionField = Table.mkField(EntityHistory.changeFieldName, EntityHistory.changeFieldType, S$RescriptSchema.never, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
153
|
-
let checkpointIdField = Table.mkField(EntityHistory.checkpointIdFieldName, EntityHistory.checkpointIdFieldType, EntityHistory.unsafeCheckpointIdSchema, undefined, undefined, undefined, true, undefined, undefined, undefined);
|
|
156
|
+
let actionField = Table.mkField(EntityHistory.changeFieldName, EntityHistory.changeFieldType, S$RescriptSchema.never, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
157
|
+
let checkpointIdField = Table.mkField(EntityHistory.checkpointIdFieldName, EntityHistory.checkpointIdFieldType, EntityHistory.unsafeCheckpointIdSchema, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined);
|
|
154
158
|
let entityTableName = entityConfig.table.tableName;
|
|
155
159
|
let historyTableName = EntityHistory.historyTableName(entityTableName, entityConfig.index);
|
|
156
|
-
let table = Table.mkTable(historyTableName, undefined,
|
|
160
|
+
let table = Table.mkTable(historyTableName, undefined, dataFields.concat([
|
|
157
161
|
checkpointIdField,
|
|
158
162
|
actionField
|
|
159
163
|
]), undefined);
|
|
@@ -210,7 +214,7 @@ GRANT ALL ON SCHEMA "` + pgSchema + `" TO public;`)
|
|
|
210
214
|
});
|
|
211
215
|
entities.forEach(entity => {
|
|
212
216
|
Table.getDerivedFromFields(entity.table).forEach(derivedFromField => {
|
|
213
|
-
let indexField = Utils.unwrapResultExn(Schema.
|
|
217
|
+
let indexField = Utils.unwrapResultExn(Schema.getDerivedFromPgFieldName(derivedSchema, derivedFromField));
|
|
214
218
|
query.contents = query.contents + "\n" + makeCreateIndexQuery(derivedFromField.derivedFromEntity, [indexField], pgSchema);
|
|
215
219
|
});
|
|
216
220
|
});
|
|
@@ -234,16 +238,69 @@ $$ LANGUAGE plpgsql;`
|
|
|
234
238
|
];
|
|
235
239
|
}
|
|
236
240
|
|
|
237
|
-
function
|
|
238
|
-
return `SELECT * FROM "` + pgSchema + `"."` + tableName + `" WHERE
|
|
241
|
+
function makeLoadQuery(pgSchema, tableName, condition) {
|
|
242
|
+
return `SELECT * FROM "` + pgSchema + `"."` + tableName + `" WHERE ` + condition + `;`;
|
|
239
243
|
}
|
|
240
244
|
|
|
241
|
-
function
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
245
|
+
function makeFilterCondition(filter, table, params) {
|
|
246
|
+
let getQueryFieldOrThrow = fieldName => {
|
|
247
|
+
let queryField = Table.queryFields(table)[fieldName];
|
|
248
|
+
if (queryField !== undefined) {
|
|
249
|
+
return queryField;
|
|
250
|
+
}
|
|
251
|
+
throw {
|
|
252
|
+
RE_EXN_ID: Persistence.StorageError,
|
|
253
|
+
message: `Failed loading "` + table.tableName + `" from storage. The table doesn't have the field "` + fieldName + `".`,
|
|
254
|
+
reason: {
|
|
255
|
+
RE_EXN_ID: Table.NonExistingTableField,
|
|
256
|
+
_1: fieldName
|
|
257
|
+
},
|
|
258
|
+
Error: new Error()
|
|
259
|
+
};
|
|
260
|
+
};
|
|
261
|
+
let serializeParamOrThrow = (queryField, fieldName, fieldValue, isArray) => {
|
|
262
|
+
let param;
|
|
263
|
+
try {
|
|
264
|
+
param = S$RescriptSchema.reverseConvertToJsonOrThrow(fieldValue, isArray ? queryField.arrayFieldSchema : queryField.fieldSchema);
|
|
265
|
+
} catch (raw_exn) {
|
|
266
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
267
|
+
throw {
|
|
268
|
+
RE_EXN_ID: Persistence.StorageError,
|
|
269
|
+
message: `Failed loading "` + table.tableName + `" from storage by field "` + fieldName + `". Couldn't serialize provided value.`,
|
|
270
|
+
reason: exn,
|
|
271
|
+
Error: new Error()
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
params.push(param);
|
|
275
|
+
return `$` + params.length.toString();
|
|
276
|
+
};
|
|
277
|
+
let scalarCondition = (fieldName, fieldValue, op) => {
|
|
278
|
+
let queryField = getQueryFieldOrThrow(fieldName);
|
|
279
|
+
return `"` + queryField.pgDbFieldName + `" ` + op + ` ` + serializeParamOrThrow(queryField, fieldName, fieldValue, false);
|
|
280
|
+
};
|
|
281
|
+
switch (filter.operator) {
|
|
282
|
+
case "=" :
|
|
283
|
+
return scalarCondition(filter.fieldName, filter.fieldValue, "=");
|
|
284
|
+
case ">" :
|
|
285
|
+
return scalarCondition(filter.fieldName, filter.fieldValue, ">");
|
|
286
|
+
case "<" :
|
|
287
|
+
return scalarCondition(filter.fieldName, filter.fieldValue, "<");
|
|
288
|
+
case "in" :
|
|
289
|
+
let fieldName = filter.fieldName;
|
|
290
|
+
let queryField = getQueryFieldOrThrow(fieldName);
|
|
291
|
+
return `"` + queryField.pgDbFieldName + `" = ANY(` + serializeParamOrThrow(queryField, fieldName, filter.fieldValue, true) + `)`;
|
|
292
|
+
case "and" :
|
|
293
|
+
let filters = filter.filters;
|
|
294
|
+
if (filters.length !== 0) {
|
|
295
|
+
return `(` + filters.map(filter => makeFilterCondition(filter, table, params)).join(" AND ") + `)`;
|
|
296
|
+
}
|
|
297
|
+
throw {
|
|
298
|
+
RE_EXN_ID: Persistence.StorageError,
|
|
299
|
+
message: `Failed loading "` + table.tableName + `" from storage. The "and" filter must contain at least one nested filter.`,
|
|
300
|
+
reason: new Error(`Empty "and" filter`),
|
|
301
|
+
Error: new Error()
|
|
302
|
+
};
|
|
303
|
+
}
|
|
247
304
|
}
|
|
248
305
|
|
|
249
306
|
function makeDeleteByIdQuery(pgSchema, tableName) {
|
|
@@ -261,7 +318,7 @@ function makeLoadAllQuery(pgSchema, tableName) {
|
|
|
261
318
|
function makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents) {
|
|
262
319
|
let match = Table.toSqlParams(table, itemSchema, pgSchema);
|
|
263
320
|
let quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
|
|
264
|
-
let primaryKeyFieldNames = Table.
|
|
321
|
+
let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table);
|
|
265
322
|
return `INSERT INTO "` + pgSchema + `"."` + table.tableName + `" (` + match.quotedFieldNames.join(", ") + `)
|
|
266
323
|
SELECT * FROM unnest(` + match.arrayFieldTypes.map((arrayFieldType, idx) => `$` + (idx + 1 | 0).toString() + `::` + arrayFieldType).join(",") + `)` + (
|
|
267
324
|
isRawEvents || primaryKeyFieldNames.length === 0 ? `` : `ON CONFLICT(` + primaryKeyFieldNames.map(fieldName => `"` + fieldName + `"`).join(",") + `) DO ` + (
|
|
@@ -274,7 +331,7 @@ function makeInsertValuesSetQuery(pgSchema, table, itemSchema, itemsCount) {
|
|
|
274
331
|
let match = Table.toSqlParams(table, itemSchema, pgSchema);
|
|
275
332
|
let quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
|
|
276
333
|
let quotedFieldNames = match.quotedFieldNames;
|
|
277
|
-
let primaryKeyFieldNames = Table.
|
|
334
|
+
let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table);
|
|
278
335
|
let fieldsCount = quotedFieldNames.length;
|
|
279
336
|
let placeholders = "";
|
|
280
337
|
for (let idx = 1; idx <= itemsCount; ++idx) {
|
|
@@ -517,15 +574,15 @@ async function deleteByIdsOrThrow(sql, pgSchema, ids, table) {
|
|
|
517
574
|
|
|
518
575
|
function makeInsertDeleteUpdatesQuery(entityConfig, pgSchema) {
|
|
519
576
|
let historyTableName = EntityHistory.historyTableName(entityConfig.name, entityConfig.index);
|
|
520
|
-
let allHistoryFieldNames =
|
|
577
|
+
let allHistoryFieldNames = Stdlib_Array.filterMap(entityConfig.table.fields, fieldOrDerived => {
|
|
521
578
|
if (fieldOrDerived.TAG === "Field") {
|
|
522
|
-
return Table.
|
|
579
|
+
return Table.getPgDbFieldName(fieldOrDerived._0);
|
|
523
580
|
}
|
|
524
581
|
});
|
|
525
582
|
allHistoryFieldNames.push(EntityHistory.checkpointIdFieldName);
|
|
526
583
|
allHistoryFieldNames.push(EntityHistory.changeFieldName);
|
|
527
|
-
let allHistoryFieldNamesStr =
|
|
528
|
-
let selectParts =
|
|
584
|
+
let allHistoryFieldNamesStr = allHistoryFieldNames.map(name => `"` + name + `"`).join(", ");
|
|
585
|
+
let selectParts = allHistoryFieldNames.map(fieldName => {
|
|
529
586
|
if (fieldName === Table.idFieldName) {
|
|
530
587
|
return `u.` + Table.idFieldName;
|
|
531
588
|
} else if (fieldName === EntityHistory.checkpointIdFieldName) {
|
|
@@ -567,12 +624,11 @@ function convertFieldsToJson(fields) {
|
|
|
567
624
|
|
|
568
625
|
function makeRawEvent(eventItem, config) {
|
|
569
626
|
let event = eventItem.event;
|
|
570
|
-
let block = event.block;
|
|
571
|
-
let logIndex = event.logIndex;
|
|
572
627
|
let blockNumber = eventItem.blockNumber;
|
|
573
628
|
let eventConfig = eventItem.eventConfig;
|
|
629
|
+
let logIndex = event.logIndex;
|
|
574
630
|
let eventId = EventUtils.packEventIndex(blockNumber, logIndex);
|
|
575
|
-
let blockFields = convertFieldsToJson(block);
|
|
631
|
+
let blockFields = convertFieldsToJson(event.block);
|
|
576
632
|
let transactionFields = convertFieldsToJson(event.transaction);
|
|
577
633
|
config.ecosystem.cleanUpRawEventFieldsInPlace(blockFields);
|
|
578
634
|
let params = S$RescriptSchema.reverseConvertOrThrow(event.params, eventConfig.paramsRawEventSchema);
|
|
@@ -585,7 +641,7 @@ function makeRawEvent(eventItem, config) {
|
|
|
585
641
|
block_number: blockNumber,
|
|
586
642
|
log_index: logIndex,
|
|
587
643
|
src_address: event.srcAddress,
|
|
588
|
-
block_hash:
|
|
644
|
+
block_hash: eventItem.blockHash,
|
|
589
645
|
block_timestamp: eventItem.timestamp,
|
|
590
646
|
block_fields: blockFields,
|
|
591
647
|
transaction_fields: transactionFields,
|
|
@@ -601,7 +657,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
601
657
|
};
|
|
602
658
|
let rawEvents;
|
|
603
659
|
if (config.enableRawEvents) {
|
|
604
|
-
let rows =
|
|
660
|
+
let rows = Stdlib_Array.filterMap(batch.items, item => {
|
|
605
661
|
if (item.kind === 0) {
|
|
606
662
|
return makeRawEvent(item, config);
|
|
607
663
|
}
|
|
@@ -621,7 +677,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
621
677
|
return classifyWriteError(specificError, InternalTable.RawEvents.table, exn);
|
|
622
678
|
}
|
|
623
679
|
};
|
|
624
|
-
let setEntities =
|
|
680
|
+
let setEntities = updatedEntities.map(param => {
|
|
625
681
|
let entityConfig = param.entityConfig;
|
|
626
682
|
let entitiesToSet = [];
|
|
627
683
|
let idsToDelete = [];
|
|
@@ -632,7 +688,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
632
688
|
let idsWithDiff = new Set();
|
|
633
689
|
let latestChangeById = {};
|
|
634
690
|
let orderedIds = [];
|
|
635
|
-
|
|
691
|
+
param.changes.forEach(change => {
|
|
636
692
|
let entityId = change.entityId;
|
|
637
693
|
if (Stdlib_Option.isNone(latestChangeById[entityId])) {
|
|
638
694
|
orderedIds.push(entityId);
|
|
@@ -653,7 +709,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
653
709
|
batchDeleteCheckpointIds.push(change.checkpointId);
|
|
654
710
|
});
|
|
655
711
|
let backfillHistoryIds = new Set();
|
|
656
|
-
|
|
712
|
+
orderedIds.forEach(entityId => {
|
|
657
713
|
let match = latestChangeById[entityId];
|
|
658
714
|
if (match.type === "SET") {
|
|
659
715
|
entitiesToSet.push(match.entity);
|
|
@@ -727,7 +783,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
727
783
|
if (rollbackTables !== undefined) {
|
|
728
784
|
await rollbackTables(sql);
|
|
729
785
|
}
|
|
730
|
-
let setOperations =
|
|
786
|
+
let setOperations = [
|
|
731
787
|
sql => InternalTable.Chains.setProgressedChains(sql, pgSchema, Utils.Dict.mapValuesToArray(batch.progressedChainsById, chainAfterBatch => ({
|
|
732
788
|
chainId: chainAfterBatch.fetchState.chainId,
|
|
733
789
|
progressBlockNumber: chainAfterBatch.progressBlockNumber,
|
|
@@ -735,14 +791,14 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
735
791
|
totalEventsProcessed: chainAfterBatch.totalEventsProcessed
|
|
736
792
|
}))),
|
|
737
793
|
setRawEvents
|
|
738
|
-
]
|
|
794
|
+
].concat(setEntities);
|
|
739
795
|
if (chainMetaData !== undefined) {
|
|
740
796
|
setOperations.push(sql => InternalTable.Chains.setMeta(sql, pgSchema, chainMetaData));
|
|
741
797
|
}
|
|
742
798
|
if (shouldSaveHistory) {
|
|
743
799
|
setOperations.push(sql => InternalTable.Checkpoints.insert(sql, pgSchema, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointBlockHashes, batch.checkpointEventsProcessed));
|
|
744
800
|
}
|
|
745
|
-
await Promise.all(
|
|
801
|
+
await Promise.all(setOperations.map(dbFunc => dbFunc(sql)));
|
|
746
802
|
if (sinkPromise === undefined) {
|
|
747
803
|
return;
|
|
748
804
|
}
|
|
@@ -752,7 +808,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
752
808
|
}
|
|
753
809
|
throw exn;
|
|
754
810
|
}),
|
|
755
|
-
Promise.all(
|
|
811
|
+
Promise.all(updatedEffectsCache.map(param => setEffectCacheOrThrow(param.effect, param.items, param.shouldInitialize)))
|
|
756
812
|
]);
|
|
757
813
|
let specificError$1 = specificError.contents;
|
|
758
814
|
if (specificError$1 === undefined) {
|
|
@@ -776,12 +832,12 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
776
832
|
}
|
|
777
833
|
|
|
778
834
|
function makeGetRollbackRestoredEntitiesQuery(entityConfig, pgSchema) {
|
|
779
|
-
let dataFieldNames =
|
|
835
|
+
let dataFieldNames = Stdlib_Array.filterMap(entityConfig.table.fields, fieldOrDerived => {
|
|
780
836
|
if (fieldOrDerived.TAG === "Field") {
|
|
781
|
-
return Table.
|
|
837
|
+
return Table.getPgDbFieldName(fieldOrDerived._0);
|
|
782
838
|
}
|
|
783
839
|
});
|
|
784
|
-
let dataFieldsCommaSeparated =
|
|
840
|
+
let dataFieldsCommaSeparated = dataFieldNames.map(name => `"` + name + `"`).join(", ");
|
|
785
841
|
let historyTableName = EntityHistory.historyTableName(entityConfig.name, entityConfig.index);
|
|
786
842
|
return `SELECT DISTINCT ON (` + Table.idFieldName + `) ` + dataFieldsCommaSeparated + `
|
|
787
843
|
FROM "` + pgSchema + `"."` + historyTableName + `"
|
|
@@ -956,70 +1012,33 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
956
1012
|
envioInfo: envioInfo
|
|
957
1013
|
};
|
|
958
1014
|
};
|
|
959
|
-
let
|
|
1015
|
+
let loadOrThrow = async (filter, table) => {
|
|
1016
|
+
let params = [];
|
|
1017
|
+
let condition = makeFilterCondition(filter, table, params);
|
|
960
1018
|
let rows;
|
|
961
1019
|
try {
|
|
962
|
-
rows = await (
|
|
963
|
-
ids.length !== 1 ? sql.unsafe(makeLoadByIdsQuery(pgSchema, table.tableName), [ids], {prepare: true}) : sql.unsafe(makeLoadByIdQuery(pgSchema, table.tableName), ids, {prepare: true})
|
|
964
|
-
);
|
|
1020
|
+
rows = await sql.unsafe(makeLoadQuery(pgSchema, table.tableName, condition), params, {prepare: true});
|
|
965
1021
|
} catch (raw_exn) {
|
|
966
1022
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
967
1023
|
throw {
|
|
968
1024
|
RE_EXN_ID: Persistence.StorageError,
|
|
969
|
-
message: `Failed loading "` + table.tableName + `" from storage by
|
|
1025
|
+
message: `Failed loading "` + table.tableName + `" from storage by condition: ` + condition,
|
|
970
1026
|
reason: exn,
|
|
971
1027
|
Error: new Error()
|
|
972
1028
|
};
|
|
973
1029
|
}
|
|
974
1030
|
try {
|
|
975
|
-
return S$RescriptSchema.parseOrThrow(rows,
|
|
1031
|
+
return S$RescriptSchema.parseOrThrow(rows, Table.pgRowsSchema(table));
|
|
976
1032
|
} catch (raw_exn$1) {
|
|
977
1033
|
let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
|
|
978
1034
|
throw {
|
|
979
1035
|
RE_EXN_ID: Persistence.StorageError,
|
|
980
|
-
message: `Failed to parse "` + table.tableName + `" loaded from storage by
|
|
1036
|
+
message: `Failed to parse "` + table.tableName + `" loaded from storage by condition: ` + condition,
|
|
981
1037
|
reason: exn$1,
|
|
982
1038
|
Error: new Error()
|
|
983
1039
|
};
|
|
984
1040
|
}
|
|
985
1041
|
};
|
|
986
|
-
let loadByFieldOrThrow = async (fieldName, fieldSchema, fieldValue, operator, table, rowsSchema) => {
|
|
987
|
-
let params;
|
|
988
|
-
try {
|
|
989
|
-
params = [S$RescriptSchema.reverseConvertToJsonOrThrow(fieldValue, fieldSchema)];
|
|
990
|
-
} catch (raw_exn) {
|
|
991
|
-
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
992
|
-
throw {
|
|
993
|
-
RE_EXN_ID: Persistence.StorageError,
|
|
994
|
-
message: `Failed loading "` + table.tableName + `" from storage by field "` + fieldName + `". Couldn't serialize provided value.`,
|
|
995
|
-
reason: exn,
|
|
996
|
-
Error: new Error()
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
let rows;
|
|
1000
|
-
try {
|
|
1001
|
-
rows = await sql.unsafe(makeLoadByFieldQuery(pgSchema, table.tableName, fieldName, operator), params, {prepare: true});
|
|
1002
|
-
} catch (raw_exn$1) {
|
|
1003
|
-
let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
|
|
1004
|
-
throw {
|
|
1005
|
-
RE_EXN_ID: Persistence.StorageError,
|
|
1006
|
-
message: `Failed loading "` + table.tableName + `" from storage by field "` + fieldName + `"`,
|
|
1007
|
-
reason: exn$1,
|
|
1008
|
-
Error: new Error()
|
|
1009
|
-
};
|
|
1010
|
-
}
|
|
1011
|
-
try {
|
|
1012
|
-
return S$RescriptSchema.parseOrThrow(rows, rowsSchema);
|
|
1013
|
-
} catch (raw_exn$2) {
|
|
1014
|
-
let exn$2 = Primitive_exceptions.internalToException(raw_exn$2);
|
|
1015
|
-
throw {
|
|
1016
|
-
RE_EXN_ID: Persistence.StorageError,
|
|
1017
|
-
message: `Failed to parse "` + table.tableName + `" loaded from storage by ids`,
|
|
1018
|
-
reason: exn$2,
|
|
1019
|
-
Error: new Error()
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
};
|
|
1023
1042
|
let setOrThrow$1 = (items, table, itemSchema) => setOrThrow(sql, items, table, itemSchema, pgSchema);
|
|
1024
1043
|
let setEffectCacheOrThrow = async (effect, items, initialize) => {
|
|
1025
1044
|
let match = effect.storageMeta;
|
|
@@ -1050,7 +1069,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1050
1069
|
return Logging.error(`Failed to dump cache. ` + psqlExec._0);
|
|
1051
1070
|
}
|
|
1052
1071
|
let psqlExec$1 = psqlExec._0;
|
|
1053
|
-
Logging.info(`Dumping cache: ` + cacheTableInfo.map(param => param.table_name + " (" +
|
|
1072
|
+
Logging.info(`Dumping cache: ` + cacheTableInfo.map(param => param.table_name + " (" + param.count.toString() + " rows)").join(", "));
|
|
1054
1073
|
let promises = cacheTableInfo.map(async param => {
|
|
1055
1074
|
let tableName = param.table_name;
|
|
1056
1075
|
let cacheName = tableName.slice(cacheTablePrefixLength);
|
|
@@ -1076,7 +1095,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1076
1095
|
let resumeInitialState = async () => {
|
|
1077
1096
|
let match = await Promise.all([
|
|
1078
1097
|
restoreEffectCache(false),
|
|
1079
|
-
InternalTable.Chains.getInitialState(sql, pgSchema).then(rawInitialStates =>
|
|
1098
|
+
InternalTable.Chains.getInitialState(sql, pgSchema).then(rawInitialStates => rawInitialStates.map(rawInitialState => ({
|
|
1080
1099
|
id: rawInitialState.id,
|
|
1081
1100
|
startBlock: rawInitialState.startBlock,
|
|
1082
1101
|
endBlock: Primitive_option.fromNull(rawInitialState.endBlock),
|
|
@@ -1093,7 +1112,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1093
1112
|
InternalTable.EnvioInfo.read(sql, pgSchema)
|
|
1094
1113
|
]);
|
|
1095
1114
|
let checkpointId = BigInt(match[2][0].id);
|
|
1096
|
-
let reorgCheckpoints =
|
|
1115
|
+
let reorgCheckpoints = match[3].map(raw => ({
|
|
1097
1116
|
id: BigInt(raw.id),
|
|
1098
1117
|
chain_id: raw.chain_id,
|
|
1099
1118
|
block_number: raw.block_number,
|
|
@@ -1156,8 +1175,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1156
1175
|
isInitialized: isInitialized,
|
|
1157
1176
|
initialize: initialize,
|
|
1158
1177
|
resumeInitialState: resumeInitialState,
|
|
1159
|
-
|
|
1160
|
-
loadByFieldOrThrow: loadByFieldOrThrow,
|
|
1178
|
+
loadOrThrow: loadOrThrow,
|
|
1161
1179
|
dumpEffectCache: dumpEffectCache,
|
|
1162
1180
|
reset: reset,
|
|
1163
1181
|
setChainMeta: setChainMeta,
|
|
@@ -1204,13 +1222,13 @@ function makeStorageFromEnv(config, sqlOpt, pgSchemaOpt, isHasuraEnabledOpt) {
|
|
|
1204
1222
|
return make(sql, Env.Db.host, pgSchema, Env.Db.port, Env.Db.user, Env.Db.database, Env.Db.password, isHasuraEnabled, tmp, isHasuraEnabled ? () => Stdlib_Promise.$$catch(Hasura.trackDatabase(Env.Hasura.graphqlEndpoint, {
|
|
1205
1223
|
role: Env.Hasura.role,
|
|
1206
1224
|
secret: Env.Hasura.secret
|
|
1207
|
-
}, pgSchema, Config.getPgUserEntities(config), Env.Hasura.aggregateEntities, Env.Hasura.responseLimit, Schema.make(
|
|
1225
|
+
}, pgSchema, Config.getPgUserEntities(config), Env.Hasura.aggregateEntities, Env.Hasura.responseLimit, Schema.make(config.allEntities.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, {
|
|
1208
1226
|
role: Env.Hasura.role,
|
|
1209
1227
|
secret: Env.Hasura.secret
|
|
1210
1228
|
}, pgSchema, tableNames.map(tableName => ({
|
|
1211
1229
|
tableName: tableName,
|
|
1212
1230
|
description: undefined,
|
|
1213
|
-
|
|
1231
|
+
columnConfigs: {}
|
|
1214
1232
|
}))), err => Promise.resolve(Logging.errorWithExn(Utils.prettifyExn(err), `Error tracking new tables`))) : undefined);
|
|
1215
1233
|
}
|
|
1216
1234
|
|
|
@@ -1233,9 +1251,8 @@ export {
|
|
|
1233
1251
|
entityHistoryCache,
|
|
1234
1252
|
getEntityHistory,
|
|
1235
1253
|
makeInitializeTransaction,
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
makeLoadByIdsQuery,
|
|
1254
|
+
makeLoadQuery,
|
|
1255
|
+
makeFilterCondition,
|
|
1239
1256
|
makeDeleteByIdQuery,
|
|
1240
1257
|
makeDeleteByIdsQuery,
|
|
1241
1258
|
makeLoadAllQuery,
|
package/src/Ports.res
ADDED
package/src/Prometheus.res
CHANGED
|
@@ -11,16 +11,16 @@ module Labels = {
|
|
|
11
11
|
let getLabelNames = (schema: S.t<'a>) =>
|
|
12
12
|
switch schema->S.classify {
|
|
13
13
|
| Object({items}) =>
|
|
14
|
-
let nonStringFields = items->
|
|
14
|
+
let nonStringFields = items->Array.reduce([], (nonStringFields, item) => {
|
|
15
15
|
if item.schema->schemaIsString {
|
|
16
16
|
nonStringFields
|
|
17
17
|
} else {
|
|
18
|
-
nonStringFields->
|
|
18
|
+
nonStringFields->Array.concat([item.location])
|
|
19
19
|
}
|
|
20
20
|
})
|
|
21
21
|
|
|
22
22
|
switch nonStringFields {
|
|
23
|
-
| [] => items->
|
|
23
|
+
| [] => items->Array.map(item => item.location)->Ok
|
|
24
24
|
| nonStringItems =>
|
|
25
25
|
let nonStringItems = nonStringItems->Array.joinUnsafe(", ")
|
|
26
26
|
Error(
|
package/src/Prometheus.res.mjs
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Utils from "./Utils.res.mjs";
|
|
4
4
|
import * as Hrtime from "./bindings/Hrtime.res.mjs";
|
|
5
|
-
import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
|
|
6
5
|
import * as PromClient from "./bindings/PromClient.res.mjs";
|
|
6
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
7
7
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
8
8
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
9
9
|
|
|
@@ -40,17 +40,17 @@ function getLabelNames(schema) {
|
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
let items = match.items;
|
|
43
|
-
let nonStringFields =
|
|
43
|
+
let nonStringFields = Stdlib_Array.reduce(items, [], (nonStringFields, item) => {
|
|
44
44
|
if (schemaIsString(item.schema)) {
|
|
45
45
|
return nonStringFields;
|
|
46
46
|
} else {
|
|
47
|
-
return
|
|
47
|
+
return nonStringFields.concat([item.location]);
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
if (nonStringFields.length === 0) {
|
|
51
51
|
return {
|
|
52
52
|
TAG: "Ok",
|
|
53
|
-
_0:
|
|
53
|
+
_0: items.map(item => item.location)
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
let nonStringItems = nonStringFields.join(", ");
|
package/src/ReorgDetection.res
CHANGED
|
@@ -53,7 +53,7 @@ let make = (
|
|
|
53
53
|
) => {
|
|
54
54
|
let dataByBlockNumber = Dict.make()
|
|
55
55
|
|
|
56
|
-
chainReorgCheckpoints->
|
|
56
|
+
chainReorgCheckpoints->Array.forEach(block => {
|
|
57
57
|
dataByBlockNumber->Utils.Dict.setByInt(
|
|
58
58
|
block.blockNumber,
|
|
59
59
|
{
|
|
@@ -161,13 +161,13 @@ let getLatestValidScannedBlock = (
|
|
|
161
161
|
|
|
162
162
|
let getPrevScannedBlockNumber = idx =>
|
|
163
163
|
ascBlockNumberKeys
|
|
164
|
-
->
|
|
164
|
+
->Array.get(idx - 1)
|
|
165
165
|
->Option.map(key => {
|
|
166
166
|
(verifiedDataByBlockNumber->Dict.getUnsafe(key)).blockNumber
|
|
167
167
|
})
|
|
168
168
|
|
|
169
169
|
let rec loop = idx => {
|
|
170
|
-
switch ascBlockNumberKeys->
|
|
170
|
+
switch ascBlockNumberKeys->Array.get(idx) {
|
|
171
171
|
| Some(blockNumberKey) =>
|
|
172
172
|
switch reorgDetection.dataByBlockNumber->Utils.Dict.dangerouslyGetNonOption(blockNumberKey) {
|
|
173
173
|
| Some(scannedBlock)
|
|
@@ -196,7 +196,7 @@ let rollbackToValidBlockNumber = (
|
|
|
196
196
|
let newDataByBlockNumber = Dict.make()
|
|
197
197
|
|
|
198
198
|
let rec loop = idx => {
|
|
199
|
-
switch ascBlockNumberKeys->
|
|
199
|
+
switch ascBlockNumberKeys->Array.get(idx) {
|
|
200
200
|
| Some(blockNumberKey) => {
|
|
201
201
|
let scannedBlock = dataByBlockNumber->Dict.getUnsafe(blockNumberKey)
|
|
202
202
|
let shouldKeep = scannedBlock.blockNumber <= blockNumber
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
|
|
4
3
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
4
|
|
|
6
5
|
function reorgDetectedToLogParams(reorgDetected, shouldRollbackOnReorg) {
|
|
@@ -17,7 +16,7 @@ function reorgDetectedToLogParams(reorgDetected, shouldRollbackOnReorg) {
|
|
|
17
16
|
|
|
18
17
|
function make(chainReorgCheckpoints, maxReorgDepth, shouldRollbackOnReorg) {
|
|
19
18
|
let dataByBlockNumber = {};
|
|
20
|
-
|
|
19
|
+
chainReorgCheckpoints.forEach(block => {
|
|
21
20
|
dataByBlockNumber[block.block_number] = {
|
|
22
21
|
blockHash: block.block_hash,
|
|
23
22
|
blockNumber: block.block_number
|
|
@@ -97,11 +96,11 @@ function getLatestValidScannedBlock(reorgDetection, blockNumbersAndHashes) {
|
|
|
97
96
|
verifiedDataByBlockNumber[blockData.blockNumber.toString()] = blockData;
|
|
98
97
|
}
|
|
99
98
|
let ascBlockNumberKeys = Object.keys(verifiedDataByBlockNumber);
|
|
100
|
-
let getPrevScannedBlockNumber = idx => Stdlib_Option.map(
|
|
99
|
+
let getPrevScannedBlockNumber = idx => Stdlib_Option.map(ascBlockNumberKeys[idx - 1 | 0], key => verifiedDataByBlockNumber[key].blockNumber);
|
|
101
100
|
let _idx = 0;
|
|
102
101
|
while (true) {
|
|
103
102
|
let idx$1 = _idx;
|
|
104
|
-
let blockNumberKey =
|
|
103
|
+
let blockNumberKey = ascBlockNumberKeys[idx$1];
|
|
105
104
|
if (blockNumberKey === undefined) {
|
|
106
105
|
return getPrevScannedBlockNumber(idx$1);
|
|
107
106
|
}
|
|
@@ -124,7 +123,7 @@ function rollbackToValidBlockNumber(param, blockNumber) {
|
|
|
124
123
|
let loop = _idx => {
|
|
125
124
|
while (true) {
|
|
126
125
|
let idx = _idx;
|
|
127
|
-
let blockNumberKey =
|
|
126
|
+
let blockNumberKey = ascBlockNumberKeys[idx];
|
|
128
127
|
if (blockNumberKey === undefined) {
|
|
129
128
|
return;
|
|
130
129
|
}
|