@secondlayer/subgraphs 0.11.7 → 1.0.0-alpha.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/dist/src/index.js +63 -60
- package/dist/src/index.js.map +6 -6
- package/dist/src/runtime/block-processor.js +17 -11
- package/dist/src/runtime/block-processor.js.map +4 -4
- package/dist/src/runtime/catchup.js +31 -28
- package/dist/src/runtime/catchup.js.map +6 -6
- package/dist/src/runtime/processor.js +49 -43
- package/dist/src/runtime/processor.js.map +8 -8
- package/dist/src/runtime/reindex.js +63 -60
- package/dist/src/runtime/reindex.js.map +6 -6
- package/dist/src/runtime/reorg.js +21 -15
- package/dist/src/runtime/reorg.js.map +5 -5
- package/dist/src/runtime/source-matcher.js.map +2 -2
- package/dist/src/runtime/stats.d.ts +1 -2
- package/dist/src/runtime/stats.js +2 -6
- package/dist/src/runtime/stats.js.map +3 -3
- package/dist/src/service.js +49 -43
- package/dist/src/service.js.map +8 -8
- package/package.json +3 -3
|
@@ -849,7 +849,10 @@ function matchSources(sources, transactions, events) {
|
|
|
849
849
|
}
|
|
850
850
|
|
|
851
851
|
// src/runtime/block-processor.ts
|
|
852
|
-
import {
|
|
852
|
+
import {
|
|
853
|
+
getSourceDb,
|
|
854
|
+
getTargetDb
|
|
855
|
+
} from "@secondlayer/shared/db";
|
|
853
856
|
import {
|
|
854
857
|
recordSubgraphProcessed,
|
|
855
858
|
updateSubgraphStatus
|
|
@@ -863,7 +866,8 @@ import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
|
|
|
863
866
|
// src/runtime/block-processor.ts
|
|
864
867
|
var schemaNameCache = new Map;
|
|
865
868
|
async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
866
|
-
const
|
|
869
|
+
const sourceDb = getSourceDb();
|
|
870
|
+
const targetDb = getTargetDb();
|
|
867
871
|
const blockStart = performance.now();
|
|
868
872
|
const result = {
|
|
869
873
|
blockHeight,
|
|
@@ -872,13 +876,15 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
872
876
|
errors: 0,
|
|
873
877
|
skipped: false
|
|
874
878
|
};
|
|
875
|
-
let block
|
|
879
|
+
let block;
|
|
880
|
+
let txs;
|
|
881
|
+
let evts;
|
|
876
882
|
if (opts?.preloaded) {
|
|
877
883
|
block = opts.preloaded.block;
|
|
878
884
|
txs = opts.preloaded.txs;
|
|
879
885
|
evts = opts.preloaded.events;
|
|
880
886
|
} else {
|
|
881
|
-
block = await
|
|
887
|
+
block = await sourceDb.selectFrom("blocks").selectAll().where("height", "=", blockHeight).executeTakeFirst();
|
|
882
888
|
if (!block) {
|
|
883
889
|
logger3.warn("Block not found for subgraph processing", {
|
|
884
890
|
subgraph: subgraphName,
|
|
@@ -895,20 +901,20 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
895
901
|
result.skipped = true;
|
|
896
902
|
return result;
|
|
897
903
|
}
|
|
898
|
-
txs = await
|
|
899
|
-
evts = await
|
|
904
|
+
txs = await sourceDb.selectFrom("transactions").selectAll().where("block_height", "=", blockHeight).execute();
|
|
905
|
+
evts = await sourceDb.selectFrom("events").selectAll().where("block_height", "=", blockHeight).execute();
|
|
900
906
|
}
|
|
901
907
|
const matched = matchSources(subgraph.sources, txs, evts);
|
|
902
908
|
result.matched = matched.length;
|
|
903
909
|
if (matched.length === 0) {
|
|
904
910
|
if (!opts?.skipProgressUpdate) {
|
|
905
|
-
await updateSubgraphStatus(
|
|
911
|
+
await updateSubgraphStatus(targetDb, subgraphName, "active", blockHeight);
|
|
906
912
|
}
|
|
907
913
|
return result;
|
|
908
914
|
}
|
|
909
915
|
let schemaName = schemaNameCache.get(subgraphName);
|
|
910
916
|
if (!schemaName) {
|
|
911
|
-
const subgraphRecord = await
|
|
917
|
+
const subgraphRecord = await targetDb.selectFrom("subgraphs").select("schema_name").where("name", "=", subgraphName).executeTakeFirst();
|
|
912
918
|
schemaName = subgraphRecord?.schema_name ?? pgSchemaName(subgraphName);
|
|
913
919
|
schemaNameCache.set(subgraphName, schemaName);
|
|
914
920
|
}
|
|
@@ -926,7 +932,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
926
932
|
};
|
|
927
933
|
let handlerMs = 0;
|
|
928
934
|
let flushMs = 0;
|
|
929
|
-
await
|
|
935
|
+
await targetDb.transaction().execute(async (tx) => {
|
|
930
936
|
const ctx = new SubgraphContext(tx, schemaName, subgraph.schema, blockMeta, initialTx);
|
|
931
937
|
const handlerStart = performance.now();
|
|
932
938
|
const runResult = await runHandlers(subgraph, matched, ctx);
|
|
@@ -957,7 +963,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
957
963
|
try {
|
|
958
964
|
const tables = Object.keys(subgraph.schema);
|
|
959
965
|
for (const table of tables) {
|
|
960
|
-
const { rows } = await sql2.raw(`SELECT n_live_tup AS count FROM pg_stat_user_tables WHERE schemaname = '${schemaName}' AND relname = '${table}'`).execute(
|
|
966
|
+
const { rows } = await sql2.raw(`SELECT n_live_tup AS count FROM pg_stat_user_tables WHERE schemaname = '${schemaName}' AND relname = '${table}'`).execute(targetDb);
|
|
961
967
|
const count = Number(rows[0]?.count ?? 0);
|
|
962
968
|
if (count >= 1e7) {
|
|
963
969
|
logger3.warn("Subgraph table exceeds 10M rows (estimate)", {
|
|
@@ -978,13 +984,11 @@ var FLUSH_INTERVAL_MS = 60000;
|
|
|
978
984
|
|
|
979
985
|
class StatsAccumulator {
|
|
980
986
|
subgraphName;
|
|
981
|
-
apiKeyId;
|
|
982
987
|
isCatchup;
|
|
983
988
|
current;
|
|
984
989
|
lastFlush = Date.now();
|
|
985
|
-
constructor(subgraphName,
|
|
990
|
+
constructor(subgraphName, isCatchup) {
|
|
986
991
|
this.subgraphName = subgraphName;
|
|
987
|
-
this.apiKeyId = apiKeyId;
|
|
988
992
|
this.isCatchup = isCatchup;
|
|
989
993
|
this.current = this.newEntry();
|
|
990
994
|
}
|
|
@@ -1009,7 +1013,6 @@ class StatsAccumulator {
|
|
|
1009
1013
|
const avgOpsPerBlock = entry.blocksProcessed > 0 ? entry.totalOps / entry.blocksProcessed : 0;
|
|
1010
1014
|
await db.insertInto("subgraph_processing_stats").values({
|
|
1011
1015
|
subgraph_name: entry.subgraphName,
|
|
1012
|
-
api_key_id: entry.apiKeyId,
|
|
1013
1016
|
bucket_start: entry.bucketStart,
|
|
1014
1017
|
bucket_end: new Date,
|
|
1015
1018
|
blocks_processed: entry.blocksProcessed,
|
|
@@ -1025,7 +1028,6 @@ class StatsAccumulator {
|
|
|
1025
1028
|
newEntry() {
|
|
1026
1029
|
return {
|
|
1027
1030
|
subgraphName: this.subgraphName,
|
|
1028
|
-
apiKeyId: this.apiKeyId,
|
|
1029
1031
|
bucketStart: new Date,
|
|
1030
1032
|
blocksProcessed: 0,
|
|
1031
1033
|
totalTimeMs: 0,
|
|
@@ -1040,7 +1042,7 @@ class StatsAccumulator {
|
|
|
1040
1042
|
}
|
|
1041
1043
|
|
|
1042
1044
|
// src/runtime/catchup.ts
|
|
1043
|
-
import {
|
|
1045
|
+
import { getSourceDb as getSourceDb2, getTargetDb as getTargetDb2 } from "@secondlayer/shared/db";
|
|
1044
1046
|
import {
|
|
1045
1047
|
recordGapBatch
|
|
1046
1048
|
} from "@secondlayer/shared/db/queries/subgraph-gaps";
|
|
@@ -1129,12 +1131,13 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
1129
1131
|
return 0;
|
|
1130
1132
|
catchingUp.add(subgraphName);
|
|
1131
1133
|
try {
|
|
1132
|
-
const
|
|
1133
|
-
const
|
|
1134
|
+
const sourceDb = getSourceDb2();
|
|
1135
|
+
const targetDb = getTargetDb2();
|
|
1136
|
+
const subgraphRow = await getSubgraph(targetDb, subgraphName);
|
|
1134
1137
|
if (!subgraphRow)
|
|
1135
1138
|
return 0;
|
|
1136
1139
|
const lastProcessedBlock = Number(subgraphRow.last_processed_block);
|
|
1137
|
-
const progress = await
|
|
1140
|
+
const progress = await sourceDb.selectFrom("index_progress").selectAll().where("network", "=", process.env.NETWORK ?? "mainnet").executeTakeFirst();
|
|
1138
1141
|
if (!progress)
|
|
1139
1142
|
return 0;
|
|
1140
1143
|
const chainTip = Number(progress.highest_seen_block);
|
|
@@ -1149,14 +1152,14 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
1149
1152
|
to: chainTip,
|
|
1150
1153
|
blocks: totalBlocks
|
|
1151
1154
|
});
|
|
1152
|
-
const stats = new StatsAccumulator(subgraphName,
|
|
1155
|
+
const stats = new StatsAccumulator(subgraphName, true);
|
|
1153
1156
|
let processed = 0;
|
|
1154
1157
|
let batchSize = DEFAULT_BATCH_SIZE;
|
|
1155
1158
|
let currentHeight = startBlock;
|
|
1156
1159
|
let nextBatchEnd = Math.min(currentHeight + batchSize - 1, chainTip);
|
|
1157
|
-
let nextBatchPromise = loadBlockRange(
|
|
1160
|
+
let nextBatchPromise = loadBlockRange(sourceDb, currentHeight, nextBatchEnd);
|
|
1158
1161
|
while (currentHeight <= chainTip) {
|
|
1159
|
-
const currentRow = await getSubgraph(
|
|
1162
|
+
const currentRow = await getSubgraph(targetDb, subgraphName);
|
|
1160
1163
|
if (!currentRow || currentRow.status !== "active") {
|
|
1161
1164
|
logger4.info("Subgraph status changed, stopping catch-up", {
|
|
1162
1165
|
subgraph: subgraphName,
|
|
@@ -1169,7 +1172,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
1169
1172
|
const nextStart = batchEnd + 1;
|
|
1170
1173
|
if (nextStart <= chainTip) {
|
|
1171
1174
|
nextBatchEnd = Math.min(nextStart + batchSize - 1, chainTip);
|
|
1172
|
-
nextBatchPromise = loadBlockRange(
|
|
1175
|
+
nextBatchPromise = loadBlockRange(sourceDb, nextStart, nextBatchEnd);
|
|
1173
1176
|
}
|
|
1174
1177
|
const batchFailedBlocks = [];
|
|
1175
1178
|
for (let height = currentHeight;height <= batchEnd; height++) {
|
|
@@ -1192,7 +1195,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
1192
1195
|
});
|
|
1193
1196
|
batchFailedBlocks.push({ height, reason: "processing_error" });
|
|
1194
1197
|
const { updateSubgraphStatus: updateSubgraphStatus2 } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
1195
|
-
await updateSubgraphStatus2(
|
|
1198
|
+
await updateSubgraphStatus2(targetDb, subgraphName, "active", height).catch(() => {});
|
|
1196
1199
|
processed++;
|
|
1197
1200
|
continue;
|
|
1198
1201
|
}
|
|
@@ -1200,7 +1203,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
1200
1203
|
if (result.timing) {
|
|
1201
1204
|
stats.record(result.timing, result.processed);
|
|
1202
1205
|
if (stats.shouldFlush()) {
|
|
1203
|
-
await stats.flush(
|
|
1206
|
+
await stats.flush(targetDb);
|
|
1204
1207
|
}
|
|
1205
1208
|
}
|
|
1206
1209
|
if (processed % LOG_INTERVAL === 0) {
|
|
@@ -1215,7 +1218,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
1215
1218
|
}
|
|
1216
1219
|
if (batchFailedBlocks.length > 0) {
|
|
1217
1220
|
const gaps = coalesceGaps(batchFailedBlocks);
|
|
1218
|
-
await recordGapBatch(
|
|
1221
|
+
await recordGapBatch(targetDb, subgraphRow.id, subgraphName, gaps).catch((err) => {
|
|
1219
1222
|
logger4.warn("Failed to record subgraph gaps", {
|
|
1220
1223
|
subgraph: subgraphName,
|
|
1221
1224
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -1226,7 +1229,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
1226
1229
|
batchSize = adjustBatchSize(batchSize, avg);
|
|
1227
1230
|
currentHeight = batchEnd + 1;
|
|
1228
1231
|
}
|
|
1229
|
-
await stats.flush(
|
|
1232
|
+
await stats.flush(targetDb);
|
|
1230
1233
|
logger4.info("Subgraph catch-up complete", {
|
|
1231
1234
|
subgraph: subgraphName,
|
|
1232
1235
|
processed
|
|
@@ -1239,13 +1242,13 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
1239
1242
|
|
|
1240
1243
|
// src/runtime/reorg.ts
|
|
1241
1244
|
import { getErrorMessage as getErrorMessage2 } from "@secondlayer/shared";
|
|
1242
|
-
import {
|
|
1245
|
+
import { getRawClient, getTargetDb as getTargetDb3 } from "@secondlayer/shared/db";
|
|
1243
1246
|
import { listSubgraphs } from "@secondlayer/shared/db/queries/subgraphs";
|
|
1244
1247
|
import { logger as logger5 } from "@secondlayer/shared/logger";
|
|
1245
1248
|
async function handleSubgraphReorg(blockHeight, loadSubgraphDef) {
|
|
1246
|
-
const
|
|
1247
|
-
const client = getRawClient();
|
|
1248
|
-
const activeSubgraphs = (await listSubgraphs(
|
|
1249
|
+
const targetDb = getTargetDb3();
|
|
1250
|
+
const client = getRawClient("target");
|
|
1251
|
+
const activeSubgraphs = (await listSubgraphs(targetDb)).filter((v) => v.status === "active");
|
|
1249
1252
|
if (activeSubgraphs.length === 0)
|
|
1250
1253
|
return;
|
|
1251
1254
|
logger5.info("Propagating reorg to subgraphs", {
|
|
@@ -1283,7 +1286,7 @@ async function handleSubgraphReorg(blockHeight, loadSubgraphDef) {
|
|
|
1283
1286
|
|
|
1284
1287
|
// src/runtime/processor.ts
|
|
1285
1288
|
import { getErrorMessage as getErrorMessage3 } from "@secondlayer/shared";
|
|
1286
|
-
import {
|
|
1289
|
+
import { getTargetDb as getTargetDb4 } from "@secondlayer/shared/db";
|
|
1287
1290
|
import {
|
|
1288
1291
|
listSubgraphs as listSubgraphs2,
|
|
1289
1292
|
updateSubgraphStatus as updateSubgraphStatus2
|
|
@@ -1293,6 +1296,9 @@ import { listen } from "@secondlayer/shared/queue/listener";
|
|
|
1293
1296
|
var CHANNEL_NEW_BLOCK = "indexer:new_block";
|
|
1294
1297
|
var DEFAULT_CONCURRENCY = 5;
|
|
1295
1298
|
var POLL_INTERVAL_MS = 5000;
|
|
1299
|
+
function sourceListenerUrl() {
|
|
1300
|
+
return process.env.SOURCE_DATABASE_URL ?? process.env.DATABASE_URL;
|
|
1301
|
+
}
|
|
1296
1302
|
function isHandlerNotFoundError(err) {
|
|
1297
1303
|
if (!(err instanceof Error))
|
|
1298
1304
|
return false;
|
|
@@ -1341,8 +1347,8 @@ async function startSubgraphProcessor(opts) {
|
|
|
1341
1347
|
const concurrency = opts?.concurrency ?? DEFAULT_CONCURRENCY;
|
|
1342
1348
|
let running = true;
|
|
1343
1349
|
logger6.info("Starting subgraph processor", { concurrency });
|
|
1344
|
-
const
|
|
1345
|
-
const activeSubgraphs = (await listSubgraphs2(
|
|
1350
|
+
const targetDb = getTargetDb4();
|
|
1351
|
+
const activeSubgraphs = (await listSubgraphs2(targetDb)).filter((v) => v.status === "active");
|
|
1346
1352
|
for (const sg of activeSubgraphs) {
|
|
1347
1353
|
try {
|
|
1348
1354
|
const def = await loadSubgraphDefinition(sg);
|
|
@@ -1350,7 +1356,7 @@ async function startSubgraphProcessor(opts) {
|
|
|
1350
1356
|
} catch (err) {
|
|
1351
1357
|
const msg = getErrorMessage3(err);
|
|
1352
1358
|
if (isHandlerNotFoundError(err)) {
|
|
1353
|
-
await updateSubgraphStatus2(
|
|
1359
|
+
await updateSubgraphStatus2(targetDb, sg.name, "error");
|
|
1354
1360
|
}
|
|
1355
1361
|
logger6.error("Subgraph catch-up failed on startup", {
|
|
1356
1362
|
subgraph: sg.name,
|
|
@@ -1361,8 +1367,8 @@ async function startSubgraphProcessor(opts) {
|
|
|
1361
1367
|
const stopListening = await listen(CHANNEL_NEW_BLOCK, async () => {
|
|
1362
1368
|
if (!running)
|
|
1363
1369
|
return;
|
|
1364
|
-
const
|
|
1365
|
-
const subgraphs = (await listSubgraphs2(
|
|
1370
|
+
const db = getTargetDb4();
|
|
1371
|
+
const subgraphs = (await listSubgraphs2(db)).filter((v) => v.status === "active");
|
|
1366
1372
|
cleanupCaches(subgraphs);
|
|
1367
1373
|
for (const sg of subgraphs) {
|
|
1368
1374
|
try {
|
|
@@ -1371,7 +1377,7 @@ async function startSubgraphProcessor(opts) {
|
|
|
1371
1377
|
} catch (err) {
|
|
1372
1378
|
const msg = getErrorMessage3(err);
|
|
1373
1379
|
if (isHandlerNotFoundError(err)) {
|
|
1374
|
-
await updateSubgraphStatus2(
|
|
1380
|
+
await updateSubgraphStatus2(db, sg.name, "error");
|
|
1375
1381
|
}
|
|
1376
1382
|
logger6.error("Subgraph processing failed", {
|
|
1377
1383
|
subgraph: sg.name,
|
|
@@ -1379,7 +1385,7 @@ async function startSubgraphProcessor(opts) {
|
|
|
1379
1385
|
});
|
|
1380
1386
|
}
|
|
1381
1387
|
}
|
|
1382
|
-
});
|
|
1388
|
+
}, { connectionString: sourceListenerUrl() });
|
|
1383
1389
|
const stopReorgListening = await listen("subgraph_reorg", async (payload) => {
|
|
1384
1390
|
if (!running)
|
|
1385
1391
|
return;
|
|
@@ -1394,12 +1400,12 @@ async function startSubgraphProcessor(opts) {
|
|
|
1394
1400
|
error: getErrorMessage3(err)
|
|
1395
1401
|
});
|
|
1396
1402
|
}
|
|
1397
|
-
});
|
|
1403
|
+
}, { connectionString: sourceListenerUrl() });
|
|
1398
1404
|
const pollInterval = setInterval(async () => {
|
|
1399
1405
|
if (!running)
|
|
1400
1406
|
return;
|
|
1401
|
-
const
|
|
1402
|
-
const subgraphs = (await listSubgraphs2(
|
|
1407
|
+
const db = getTargetDb4();
|
|
1408
|
+
const subgraphs = (await listSubgraphs2(db)).filter((v) => v.status === "active");
|
|
1403
1409
|
cleanupCaches(subgraphs);
|
|
1404
1410
|
for (const sg of subgraphs) {
|
|
1405
1411
|
try {
|
|
@@ -1426,5 +1432,5 @@ export {
|
|
|
1426
1432
|
startSubgraphProcessor
|
|
1427
1433
|
};
|
|
1428
1434
|
|
|
1429
|
-
//# debugId=
|
|
1435
|
+
//# debugId=F8E2C460E99ED57564756E2164756E21
|
|
1430
1436
|
//# sourceMappingURL=processor.js.map
|