@secondlayer/subgraphs 3.10.0 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/src/index.d.ts +29 -1
- package/dist/src/index.js +78 -3
- package/dist/src/index.js.map +6 -6
- package/dist/src/runtime/block-processor.d.ts +3 -0
- package/dist/src/runtime/block-processor.js +43 -3
- package/dist/src/runtime/block-processor.js.map +3 -3
- package/dist/src/runtime/catchup.d.ts +3 -0
- package/dist/src/runtime/catchup.js +43 -3
- package/dist/src/runtime/catchup.js.map +3 -3
- package/dist/src/runtime/processor.js +102 -4
- package/dist/src/runtime/processor.js.map +5 -5
- package/dist/src/runtime/reindex.d.ts +7 -0
- package/dist/src/runtime/reindex.js +74 -3
- package/dist/src/runtime/reindex.js.map +4 -4
- package/dist/src/runtime/reorg.d.ts +3 -0
- package/dist/src/runtime/reorg.js +43 -3
- package/dist/src/runtime/reorg.js.map +3 -3
- package/dist/src/runtime/replay.js +43 -3
- package/dist/src/runtime/replay.js.map +3 -3
- package/dist/src/runtime/runner.d.ts +3 -0
- package/dist/src/schema/index.d.ts +3 -0
- package/dist/src/schema/index.js +2 -1
- package/dist/src/schema/index.js.map +4 -4
- package/dist/src/service.js +102 -4
- package/dist/src/service.js.map +5 -5
- package/dist/src/types.d.ts +3 -0
- package/dist/src/validate.d.ts +3 -0
- package/dist/src/validate.js +2 -1
- package/dist/src/validate.js.map +3 -3
- package/package.json +2 -2
|
@@ -196,6 +196,9 @@ interface SubgraphDefinition {
|
|
|
196
196
|
description?: string;
|
|
197
197
|
/** Block height to start indexing from (default: 1) */
|
|
198
198
|
startBlock?: number;
|
|
199
|
+
/** 'concurrent' = tip-first: live at tip now, history backfills behind.
|
|
200
|
+
* Requires order-tolerant handlers. Default 'blocking'. */
|
|
201
|
+
backfillMode?: "blocking" | "concurrent";
|
|
199
202
|
/** Named source filters — keys become handler keys */
|
|
200
203
|
sources: Record<string, SubgraphFilter>;
|
|
201
204
|
/** Tables in this subgraph */
|
|
@@ -225,6 +228,8 @@ interface ReindexOptions {
|
|
|
225
228
|
fromBlock?: number;
|
|
226
229
|
toBlock?: number;
|
|
227
230
|
schemaName?: string;
|
|
231
|
+
/** Op row to receive processed_events on each progress flush. */
|
|
232
|
+
operationId?: string;
|
|
228
233
|
signal?: AbortSignal;
|
|
229
234
|
}
|
|
230
235
|
/**
|
|
@@ -242,6 +247,7 @@ declare function reindexSubgraph(def: SubgraphDefinition, opts?: ReindexOptions)
|
|
|
242
247
|
*/
|
|
243
248
|
declare function resumeReindex(def: SubgraphDefinition, opts: {
|
|
244
249
|
schemaName: string
|
|
250
|
+
operationId?: string
|
|
245
251
|
signal?: AbortSignal
|
|
246
252
|
}): Promise<{
|
|
247
253
|
processed: number
|
|
@@ -255,6 +261,7 @@ declare function backfillSubgraph(def: SubgraphDefinition, opts: {
|
|
|
255
261
|
fromBlock: number
|
|
256
262
|
toBlock: number
|
|
257
263
|
schemaName?: string
|
|
264
|
+
operationId?: string
|
|
258
265
|
signal?: AbortSignal
|
|
259
266
|
}): Promise<{
|
|
260
267
|
processed: number
|
|
@@ -1119,6 +1119,28 @@ function reconstructEvent(e) {
|
|
|
1119
1119
|
}
|
|
1120
1120
|
|
|
1121
1121
|
// src/runtime/block-source.ts
|
|
1122
|
+
function canSparseScan(subgraph) {
|
|
1123
|
+
if (Array.isArray(subgraph.sources))
|
|
1124
|
+
return false;
|
|
1125
|
+
const filters = sourceFilters(subgraph);
|
|
1126
|
+
if (filters.length === 0)
|
|
1127
|
+
return false;
|
|
1128
|
+
return filters.every((f) => Boolean(EVENT_FILTER_TO_INDEX_TYPE[f.type]));
|
|
1129
|
+
}
|
|
1130
|
+
function sparseProbeTargets(subgraph) {
|
|
1131
|
+
const targets = new Map;
|
|
1132
|
+
for (const f of sourceFilters(subgraph)) {
|
|
1133
|
+
const eventType = EVENT_FILTER_TO_INDEX_TYPE[f.type];
|
|
1134
|
+
if (!eventType)
|
|
1135
|
+
continue;
|
|
1136
|
+
const scoped = f;
|
|
1137
|
+
const contractId = scoped.contractId ?? scoped.assetIdentifier?.split("::")[0];
|
|
1138
|
+
const key = `${eventType}|${contractId ?? ""}`;
|
|
1139
|
+
targets.set(key, { eventType, ...contractId ? { contractId } : {} });
|
|
1140
|
+
}
|
|
1141
|
+
return [...targets.values()];
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1122
1144
|
class PostgresBlockSource {
|
|
1123
1145
|
async getTip() {
|
|
1124
1146
|
const progress = await getSourceDb().selectFrom("index_progress").selectAll().where("network", "=", process.env.NETWORK ?? "mainnet").executeTakeFirst();
|
|
@@ -1181,9 +1203,18 @@ function isStreamsIndexEligible(subgraph) {
|
|
|
1181
1203
|
class PublicApiBlockSource {
|
|
1182
1204
|
http;
|
|
1183
1205
|
eventTypes;
|
|
1184
|
-
|
|
1206
|
+
probeTargets;
|
|
1207
|
+
constructor(http, eventTypes, probeTargets) {
|
|
1185
1208
|
this.http = http;
|
|
1186
1209
|
this.eventTypes = eventTypes;
|
|
1210
|
+
this.probeTargets = probeTargets;
|
|
1211
|
+
}
|
|
1212
|
+
async nextDataHeight(afterHeight, untilHeight) {
|
|
1213
|
+
if (!this.probeTargets?.length)
|
|
1214
|
+
return afterHeight + 1;
|
|
1215
|
+
const hits = await Promise.all(this.probeTargets.map((t) => this.http.firstEventHeight(t.eventType, afterHeight + 1, untilHeight, t.contractId)));
|
|
1216
|
+
const found = hits.filter((h) => h !== null);
|
|
1217
|
+
return found.length ? Math.min(...found) : null;
|
|
1187
1218
|
}
|
|
1188
1219
|
getTip() {
|
|
1189
1220
|
return this.http.getIndexTip();
|
|
@@ -1247,6 +1278,15 @@ class FallbackBlockSource {
|
|
|
1247
1278
|
return this.fallback.loadBlockRange(fromHeight, toHeight);
|
|
1248
1279
|
}
|
|
1249
1280
|
}
|
|
1281
|
+
async nextDataHeight(afterHeight, untilHeight) {
|
|
1282
|
+
if (!this.primary.nextDataHeight)
|
|
1283
|
+
return afterHeight + 1;
|
|
1284
|
+
try {
|
|
1285
|
+
return await this.primary.nextDataHeight(afterHeight, untilHeight);
|
|
1286
|
+
} catch {
|
|
1287
|
+
return afterHeight + 1;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1250
1290
|
}
|
|
1251
1291
|
var postgresBlockSource = new PostgresBlockSource;
|
|
1252
1292
|
function buildHttpClient() {
|
|
@@ -1259,7 +1299,7 @@ function buildHttpClient() {
|
|
|
1259
1299
|
}
|
|
1260
1300
|
function resolveBlockSource(subgraph) {
|
|
1261
1301
|
if (process.env.SUBGRAPH_SOURCE === "streams-index" && subgraph && isStreamsIndexEligible(subgraph)) {
|
|
1262
|
-
return new FallbackBlockSource(new PublicApiBlockSource(buildHttpClient(), referencedIndexEventTypes(subgraph)), postgresBlockSource);
|
|
1302
|
+
return new FallbackBlockSource(new PublicApiBlockSource(buildHttpClient(), referencedIndexEventTypes(subgraph), canSparseScan(subgraph) ? sparseProbeTargets(subgraph) : undefined), postgresBlockSource);
|
|
1263
1303
|
}
|
|
1264
1304
|
if (process.env.SUBGRAPH_SOURCE === "streams-index" && subgraph) {
|
|
1265
1305
|
logger3.debug("Subgraph not streams-index eligible, using DB tap", {
|
|
@@ -1742,6 +1782,7 @@ import {
|
|
|
1742
1782
|
recordGapBatch,
|
|
1743
1783
|
resolveGaps
|
|
1744
1784
|
} from "@secondlayer/shared/db/queries/subgraph-gaps";
|
|
1785
|
+
import { updateOperationProcessedEvents } from "@secondlayer/shared/db/queries/subgraph-operations";
|
|
1745
1786
|
import {
|
|
1746
1787
|
recordSubgraphProcessed as recordSubgraphProcessed2,
|
|
1747
1788
|
updateSubgraphStatus as updateSubgraphStatus2
|
|
@@ -1929,6 +1970,7 @@ async function processBlockRange(def, opts) {
|
|
|
1929
1970
|
let batchSize = batchConfig.defaultBatchSize;
|
|
1930
1971
|
let currentHeight = fromBlock;
|
|
1931
1972
|
let aborted = false;
|
|
1973
|
+
const sparse = Boolean(source.nextDataHeight && canSparseScan(def));
|
|
1932
1974
|
const flushHealth = async () => {
|
|
1933
1975
|
if (pendingEventsProcessed === 0 && pendingErrors === 0)
|
|
1934
1976
|
return;
|
|
@@ -1959,6 +2001,7 @@ async function processBlockRange(def, opts) {
|
|
|
1959
2001
|
nextBatchPromise = source.loadBlockRange(nextStart, nextBatchEnd);
|
|
1960
2002
|
}
|
|
1961
2003
|
const batchFailedBlocks = [];
|
|
2004
|
+
let batchMatched = 0;
|
|
1962
2005
|
for (let height = currentHeight;height <= batchEnd; height++) {
|
|
1963
2006
|
const blockData = batch.get(height);
|
|
1964
2007
|
if (!blockData) {
|
|
@@ -1988,6 +2031,7 @@ async function processBlockRange(def, opts) {
|
|
|
1988
2031
|
continue;
|
|
1989
2032
|
}
|
|
1990
2033
|
blocksProcessed++;
|
|
2034
|
+
batchMatched += result.matched;
|
|
1991
2035
|
totalEventsProcessed += result.processed;
|
|
1992
2036
|
totalErrors += result.errors;
|
|
1993
2037
|
pendingEventsProcessed += result.processed;
|
|
@@ -2005,6 +2049,9 @@ async function processBlockRange(def, opts) {
|
|
|
2005
2049
|
const shouldFlushProgress = blocksProcessed % 100 === 0 || now - lastProgressFlushAt >= PROGRESS_FLUSH_INTERVAL_MS;
|
|
2006
2050
|
if (shouldFlushProgress) {
|
|
2007
2051
|
await updateSubgraphStatus2(targetDb, subgraphName, status, height);
|
|
2052
|
+
if (opts.operationId) {
|
|
2053
|
+
await updateOperationProcessedEvents(targetDb, opts.operationId, totalEventsProcessed).catch(() => {});
|
|
2054
|
+
}
|
|
2008
2055
|
lastProgressFlushAt = now;
|
|
2009
2056
|
}
|
|
2010
2057
|
if (blocksProcessed % LOG_INTERVAL === 0) {
|
|
@@ -2033,6 +2080,27 @@ async function processBlockRange(def, opts) {
|
|
|
2033
2080
|
});
|
|
2034
2081
|
});
|
|
2035
2082
|
}
|
|
2083
|
+
if (sparse && batchMatched === 0 && batchEnd < toBlock && source.nextDataHeight) {
|
|
2084
|
+
const next = await source.nextDataHeight(batchEnd, toBlock);
|
|
2085
|
+
const jumpTo = next === null ? toBlock + 1 : Math.max(next, batchEnd + 1);
|
|
2086
|
+
if (jumpTo > batchEnd + 1) {
|
|
2087
|
+
const skipped = Math.min(jumpTo, toBlock + 1) - (batchEnd + 1);
|
|
2088
|
+
blocksProcessed += skipped;
|
|
2089
|
+
await updateSubgraphStatus2(targetDb, subgraphName, status, jumpTo - 1);
|
|
2090
|
+
logger6.info("Sparse skip", {
|
|
2091
|
+
subgraph: subgraphName,
|
|
2092
|
+
from: batchEnd + 1,
|
|
2093
|
+
to: jumpTo - 1,
|
|
2094
|
+
skipped
|
|
2095
|
+
});
|
|
2096
|
+
currentHeight = jumpTo;
|
|
2097
|
+
if (currentHeight <= toBlock) {
|
|
2098
|
+
nextBatchEnd = Math.min(currentHeight + batchSize - 1, toBlock);
|
|
2099
|
+
nextBatchPromise = source.loadBlockRange(currentHeight, nextBatchEnd);
|
|
2100
|
+
}
|
|
2101
|
+
continue;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2036
2104
|
const avg = avgEventsPerBlock(batch);
|
|
2037
2105
|
if (avg > 50)
|
|
2038
2106
|
batchSize = Math.max(Math.round(batchSize * 0.5), batchConfig.minBatchSize);
|
|
@@ -2101,6 +2169,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
2101
2169
|
isCatchup: false,
|
|
2102
2170
|
apiKeyId: null,
|
|
2103
2171
|
subgraphId: subgraphRow?.id,
|
|
2172
|
+
operationId: opts?.operationId,
|
|
2104
2173
|
signal: opts?.signal
|
|
2105
2174
|
});
|
|
2106
2175
|
if (result.aborted) {
|
|
@@ -2176,6 +2245,7 @@ async function resumeReindex(def, opts) {
|
|
|
2176
2245
|
isCatchup: false,
|
|
2177
2246
|
apiKeyId: null,
|
|
2178
2247
|
subgraphId: row.id,
|
|
2248
|
+
operationId: opts.operationId,
|
|
2179
2249
|
signal: opts.signal
|
|
2180
2250
|
});
|
|
2181
2251
|
if (result.aborted) {
|
|
@@ -2224,6 +2294,7 @@ async function backfillSubgraph(def, opts) {
|
|
|
2224
2294
|
isCatchup: false,
|
|
2225
2295
|
apiKeyId: null,
|
|
2226
2296
|
subgraphId: subgraphRow?.id,
|
|
2297
|
+
operationId: opts.operationId,
|
|
2227
2298
|
signal: opts.signal
|
|
2228
2299
|
});
|
|
2229
2300
|
if (result.aborted) {
|
|
@@ -2261,5 +2332,5 @@ export {
|
|
|
2261
2332
|
backfillSubgraph
|
|
2262
2333
|
};
|
|
2263
2334
|
|
|
2264
|
-
//# debugId=
|
|
2335
|
+
//# debugId=BBB610F8B1974F6264756E2164756E21
|
|
2265
2336
|
//# sourceMappingURL=reindex.js.map
|