@secondlayer/subgraphs 0.6.0 → 0.7.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.d.ts +1 -1
- package/dist/src/index.js +226 -114
- package/dist/src/index.js.map +16 -16
- package/dist/src/runtime/block-processor.js +130 -100
- package/dist/src/runtime/block-processor.js.map +9 -9
- package/dist/src/runtime/catchup.js +177 -102
- package/dist/src/runtime/catchup.js.map +12 -12
- package/dist/src/runtime/clarity.js.map +2 -2
- package/dist/src/runtime/context.d.ts +1 -1
- package/dist/src/runtime/context.js +17 -4
- package/dist/src/runtime/context.js.map +3 -3
- package/dist/src/runtime/processor.js +195 -108
- package/dist/src/runtime/processor.js.map +14 -14
- package/dist/src/runtime/reindex.js +219 -113
- package/dist/src/runtime/reindex.js.map +13 -13
- package/dist/src/runtime/reorg.js +143 -104
- package/dist/src/runtime/reorg.js.map +10 -10
- package/dist/src/runtime/runner.d.ts +1 -1
- package/dist/src/runtime/runner.js +7 -3
- package/dist/src/runtime/runner.js.map +4 -4
- package/dist/src/runtime/source-matcher.js.map +3 -3
- package/dist/src/runtime/stats.d.ts +1 -1
- package/dist/src/runtime/stats.js +2 -2
- package/dist/src/runtime/stats.js.map +3 -3
- package/dist/src/schema/index.d.ts +1 -1
- package/dist/src/schema/index.js +8 -2
- package/dist/src/schema/index.js.map +5 -5
- package/dist/src/service.js +196 -109
- package/dist/src/service.js.map +15 -15
- package/dist/src/templates.js.map +2 -2
- package/dist/src/types.js.map +2 -2
- package/dist/src/validate.js.map +2 -2
- package/package.json +51 -51
package/dist/src/index.d.ts
CHANGED
|
@@ -138,8 +138,8 @@ interface GeneratedSQL {
|
|
|
138
138
|
*/
|
|
139
139
|
declare function generateSubgraphSQL(def: SubgraphDefinition, schemaNameOverride?: string): GeneratedSQL;
|
|
140
140
|
import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
|
|
141
|
-
import { Kysely } from "kysely";
|
|
142
141
|
import { Database } from "@secondlayer/shared/db";
|
|
142
|
+
import { Kysely } from "kysely";
|
|
143
143
|
type AnyDb = Kysely<Database>;
|
|
144
144
|
interface TableDiff {
|
|
145
145
|
/** Tables added to the schema */
|
package/dist/src/index.js
CHANGED
|
@@ -60,8 +60,8 @@ function validateSubgraphDefinition(def) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// src/runtime/context.ts
|
|
63
|
-
import { sql } from "kysely";
|
|
64
63
|
import { logger } from "@secondlayer/shared/logger";
|
|
64
|
+
import { sql } from "kysely";
|
|
65
65
|
function validateColumnName(name) {
|
|
66
66
|
if (!/^[a-z_][a-z0-9_]*$/i.test(name)) {
|
|
67
67
|
throw new Error(`Invalid column name: ${name}`);
|
|
@@ -102,13 +102,26 @@ class SubgraphContext {
|
|
|
102
102
|
const keyColumns = Object.keys(key);
|
|
103
103
|
const hasUniqueConstraint = tableDef.uniqueKeys?.some((uk) => uk.length === keyColumns.length && uk.every((c) => keyColumns.includes(c)));
|
|
104
104
|
if (hasUniqueConstraint) {
|
|
105
|
-
this.ops.push({
|
|
105
|
+
this.ops.push({
|
|
106
|
+
kind: "insert",
|
|
107
|
+
table,
|
|
108
|
+
data: { ...key, ...row, _upsert_keys: keyColumns }
|
|
109
|
+
});
|
|
106
110
|
} else {
|
|
107
111
|
logger.warn("upsert called without matching uniqueKeys constraint, using fallback", {
|
|
108
112
|
table,
|
|
109
113
|
keys: keyColumns
|
|
110
114
|
});
|
|
111
|
-
this.ops.push({
|
|
115
|
+
this.ops.push({
|
|
116
|
+
kind: "insert",
|
|
117
|
+
table,
|
|
118
|
+
data: {
|
|
119
|
+
...key,
|
|
120
|
+
...row,
|
|
121
|
+
_upsert_fallback_keys: keyColumns,
|
|
122
|
+
_upsert_fallback_set: row
|
|
123
|
+
}
|
|
124
|
+
});
|
|
112
125
|
}
|
|
113
126
|
}
|
|
114
127
|
delete(table, where) {
|
|
@@ -271,95 +284,6 @@ function buildWhereClause(where) {
|
|
|
271
284
|
return { clause: parts.join(" AND "), values: [] };
|
|
272
285
|
}
|
|
273
286
|
|
|
274
|
-
// src/runtime/source-matcher.ts
|
|
275
|
-
function matchPattern(value, pattern) {
|
|
276
|
-
if (!pattern.includes("*"))
|
|
277
|
-
return value === pattern;
|
|
278
|
-
const regex = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
279
|
-
return new RegExp(`^${regex}$`).test(value);
|
|
280
|
-
}
|
|
281
|
-
function matchSource(source, transactions, eventsByTx) {
|
|
282
|
-
const results = [];
|
|
283
|
-
const key = sourceKey(source);
|
|
284
|
-
for (const tx of transactions) {
|
|
285
|
-
if (source.type) {
|
|
286
|
-
if (!matchPattern(tx.type, source.type))
|
|
287
|
-
continue;
|
|
288
|
-
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
289
|
-
let matchedEvents = txEvents;
|
|
290
|
-
if (source.minAmount !== undefined) {
|
|
291
|
-
const amountEvents = matchedEvents.filter((e) => {
|
|
292
|
-
const data = e.data;
|
|
293
|
-
const rawAmount = data?.amount;
|
|
294
|
-
if (rawAmount === undefined)
|
|
295
|
-
return false;
|
|
296
|
-
const amount = BigInt(rawAmount);
|
|
297
|
-
return amount >= source.minAmount;
|
|
298
|
-
});
|
|
299
|
-
if (amountEvents.length === 0)
|
|
300
|
-
continue;
|
|
301
|
-
matchedEvents = amountEvents;
|
|
302
|
-
}
|
|
303
|
-
results.push({ tx, events: matchedEvents, sourceKey: key });
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
306
|
-
if (source.contract) {
|
|
307
|
-
const txContractMatch = tx.contract_id && matchPattern(tx.contract_id, source.contract);
|
|
308
|
-
if (source.function && tx.function_name) {
|
|
309
|
-
if (!matchPattern(tx.function_name, source.function))
|
|
310
|
-
continue;
|
|
311
|
-
} else if (source.function && !tx.function_name) {
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
315
|
-
let matchedEvents = txEvents;
|
|
316
|
-
if (!txContractMatch) {
|
|
317
|
-
matchedEvents = txEvents.filter((e) => {
|
|
318
|
-
const data = e.data;
|
|
319
|
-
const contractIdentifier = data?.contract_identifier;
|
|
320
|
-
return contractIdentifier && matchPattern(contractIdentifier, source.contract);
|
|
321
|
-
});
|
|
322
|
-
if (matchedEvents.length === 0)
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
if (source.event) {
|
|
326
|
-
matchedEvents = matchedEvents.filter((e) => {
|
|
327
|
-
if (matchPattern(e.type, source.event))
|
|
328
|
-
return true;
|
|
329
|
-
const data = e.data;
|
|
330
|
-
const topic = data?.topic;
|
|
331
|
-
return topic ? matchPattern(topic, source.event) : false;
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
if (txContractMatch || matchedEvents.length > 0) {
|
|
335
|
-
results.push({ tx, events: matchedEvents, sourceKey: key });
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return results;
|
|
340
|
-
}
|
|
341
|
-
function matchSources(sources, transactions, events) {
|
|
342
|
-
const eventsByTx = new Map;
|
|
343
|
-
for (const event of events) {
|
|
344
|
-
const list = eventsByTx.get(event.tx_id) ?? [];
|
|
345
|
-
list.push(event);
|
|
346
|
-
eventsByTx.set(event.tx_id, list);
|
|
347
|
-
}
|
|
348
|
-
const seen = new Set;
|
|
349
|
-
const results = [];
|
|
350
|
-
for (const source of sources) {
|
|
351
|
-
const matches = matchSource(source, transactions, eventsByTx);
|
|
352
|
-
for (const match of matches) {
|
|
353
|
-
const dedupeKey = `${match.tx.tx_id}:${match.sourceKey}`;
|
|
354
|
-
if (!seen.has(dedupeKey)) {
|
|
355
|
-
seen.add(dedupeKey);
|
|
356
|
-
results.push(match);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
return results;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
287
|
// src/runtime/clarity.ts
|
|
364
288
|
import { cvToJSON, deserializeCV } from "@secondlayer/stacks/clarity";
|
|
365
289
|
function decodeClarityValue(hex) {
|
|
@@ -392,8 +316,8 @@ function decodeFunctionArgs(args) {
|
|
|
392
316
|
}
|
|
393
317
|
|
|
394
318
|
// src/runtime/runner.ts
|
|
395
|
-
import { logger as logger2 } from "@secondlayer/shared/logger";
|
|
396
319
|
import { getErrorMessage } from "@secondlayer/shared";
|
|
320
|
+
import { logger as logger2 } from "@secondlayer/shared/logger";
|
|
397
321
|
var DEFAULT_ERROR_THRESHOLD = 50;
|
|
398
322
|
function resolveHandler(handlers, key) {
|
|
399
323
|
return handlers[key] ?? handlers["*"] ?? null;
|
|
@@ -405,7 +329,11 @@ async function runHandlers(subgraph, matched, ctx, opts) {
|
|
|
405
329
|
for (const { tx, events, sourceKey: sourceKey2 } of matched) {
|
|
406
330
|
const handler = resolveHandler(subgraph.handlers, sourceKey2);
|
|
407
331
|
if (!handler) {
|
|
408
|
-
logger2.warn("No handler found for source key", {
|
|
332
|
+
logger2.warn("No handler found for source key", {
|
|
333
|
+
subgraph: subgraph.name,
|
|
334
|
+
sourceKey: sourceKey2,
|
|
335
|
+
txId: tx.tx_id
|
|
336
|
+
});
|
|
409
337
|
continue;
|
|
410
338
|
}
|
|
411
339
|
ctx.setTx({
|
|
@@ -482,11 +410,103 @@ async function runHandlers(subgraph, matched, ctx, opts) {
|
|
|
482
410
|
return { processed, errors };
|
|
483
411
|
}
|
|
484
412
|
|
|
413
|
+
// src/runtime/source-matcher.ts
|
|
414
|
+
function matchPattern(value, pattern) {
|
|
415
|
+
if (!pattern.includes("*"))
|
|
416
|
+
return value === pattern;
|
|
417
|
+
const regex = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
418
|
+
return new RegExp(`^${regex}$`).test(value);
|
|
419
|
+
}
|
|
420
|
+
function matchSource(source, transactions, eventsByTx) {
|
|
421
|
+
const results = [];
|
|
422
|
+
const key = sourceKey(source);
|
|
423
|
+
for (const tx of transactions) {
|
|
424
|
+
if (source.type) {
|
|
425
|
+
if (!matchPattern(tx.type, source.type))
|
|
426
|
+
continue;
|
|
427
|
+
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
428
|
+
let matchedEvents = txEvents;
|
|
429
|
+
if (source.minAmount !== undefined) {
|
|
430
|
+
const amountEvents = matchedEvents.filter((e) => {
|
|
431
|
+
const data = e.data;
|
|
432
|
+
const rawAmount = data?.amount;
|
|
433
|
+
if (rawAmount === undefined)
|
|
434
|
+
return false;
|
|
435
|
+
const amount = BigInt(rawAmount);
|
|
436
|
+
return amount >= source.minAmount;
|
|
437
|
+
});
|
|
438
|
+
if (amountEvents.length === 0)
|
|
439
|
+
continue;
|
|
440
|
+
matchedEvents = amountEvents;
|
|
441
|
+
}
|
|
442
|
+
results.push({ tx, events: matchedEvents, sourceKey: key });
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (source.contract) {
|
|
446
|
+
const txContractMatch = tx.contract_id && matchPattern(tx.contract_id, source.contract);
|
|
447
|
+
if (source.function && tx.function_name) {
|
|
448
|
+
if (!matchPattern(tx.function_name, source.function))
|
|
449
|
+
continue;
|
|
450
|
+
} else if (source.function && !tx.function_name) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
const txEvents = eventsByTx.get(tx.tx_id) ?? [];
|
|
454
|
+
let matchedEvents = txEvents;
|
|
455
|
+
if (!txContractMatch) {
|
|
456
|
+
matchedEvents = txEvents.filter((e) => {
|
|
457
|
+
const data = e.data;
|
|
458
|
+
const contractIdentifier = data?.contract_identifier;
|
|
459
|
+
return contractIdentifier && matchPattern(contractIdentifier, source.contract);
|
|
460
|
+
});
|
|
461
|
+
if (matchedEvents.length === 0)
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
if (source.event) {
|
|
465
|
+
matchedEvents = matchedEvents.filter((e) => {
|
|
466
|
+
if (matchPattern(e.type, source.event))
|
|
467
|
+
return true;
|
|
468
|
+
const data = e.data;
|
|
469
|
+
const topic = data?.topic;
|
|
470
|
+
return topic ? matchPattern(topic, source.event) : false;
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
if (txContractMatch || matchedEvents.length > 0) {
|
|
474
|
+
results.push({ tx, events: matchedEvents, sourceKey: key });
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return results;
|
|
479
|
+
}
|
|
480
|
+
function matchSources(sources, transactions, events) {
|
|
481
|
+
const eventsByTx = new Map;
|
|
482
|
+
for (const event of events) {
|
|
483
|
+
const list = eventsByTx.get(event.tx_id) ?? [];
|
|
484
|
+
list.push(event);
|
|
485
|
+
eventsByTx.set(event.tx_id, list);
|
|
486
|
+
}
|
|
487
|
+
const seen = new Set;
|
|
488
|
+
const results = [];
|
|
489
|
+
for (const source of sources) {
|
|
490
|
+
const matches = matchSource(source, transactions, eventsByTx);
|
|
491
|
+
for (const match of matches) {
|
|
492
|
+
const dedupeKey = `${match.tx.tx_id}:${match.sourceKey}`;
|
|
493
|
+
if (!seen.has(dedupeKey)) {
|
|
494
|
+
seen.add(dedupeKey);
|
|
495
|
+
results.push(match);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return results;
|
|
500
|
+
}
|
|
501
|
+
|
|
485
502
|
// src/runtime/block-processor.ts
|
|
486
|
-
import { sql as sql2 } from "kysely";
|
|
487
503
|
import { getDb } from "@secondlayer/shared/db";
|
|
504
|
+
import {
|
|
505
|
+
recordSubgraphProcessed,
|
|
506
|
+
updateSubgraphStatus
|
|
507
|
+
} from "@secondlayer/shared/db/queries/subgraphs";
|
|
488
508
|
import { logger as logger3 } from "@secondlayer/shared/logger";
|
|
489
|
-
import {
|
|
509
|
+
import { sql as sql2 } from "kysely";
|
|
490
510
|
|
|
491
511
|
// src/schema/utils.ts
|
|
492
512
|
import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
|
|
@@ -511,12 +531,18 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
511
531
|
} else {
|
|
512
532
|
block = await db.selectFrom("blocks").selectAll().where("height", "=", blockHeight).executeTakeFirst();
|
|
513
533
|
if (!block) {
|
|
514
|
-
logger3.warn("Block not found for subgraph processing", {
|
|
534
|
+
logger3.warn("Block not found for subgraph processing", {
|
|
535
|
+
subgraph: subgraphName,
|
|
536
|
+
blockHeight
|
|
537
|
+
});
|
|
515
538
|
result.skipped = true;
|
|
516
539
|
return result;
|
|
517
540
|
}
|
|
518
541
|
if (!block.canonical) {
|
|
519
|
-
logger3.debug("Skipping non-canonical block", {
|
|
542
|
+
logger3.debug("Skipping non-canonical block", {
|
|
543
|
+
subgraph: subgraphName,
|
|
544
|
+
blockHeight
|
|
545
|
+
});
|
|
520
546
|
result.skipped = true;
|
|
521
547
|
return result;
|
|
522
548
|
}
|
|
@@ -585,7 +611,11 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
585
611
|
const { rows } = await sql2.raw(`SELECT COUNT(*) as count FROM "${schemaName}"."${table}"`).execute(db);
|
|
586
612
|
const count = Number(rows[0].count);
|
|
587
613
|
if (count >= 1e7) {
|
|
588
|
-
logger3.warn("Subgraph table exceeds 10M rows", {
|
|
614
|
+
logger3.warn("Subgraph table exceeds 10M rows", {
|
|
615
|
+
subgraph: subgraphName,
|
|
616
|
+
table,
|
|
617
|
+
count
|
|
618
|
+
});
|
|
589
619
|
}
|
|
590
620
|
}
|
|
591
621
|
} catch {}
|
|
@@ -639,7 +669,7 @@ class StatsAccumulator {
|
|
|
639
669
|
flush_time_ms: Math.round(entry.flushTimeMs),
|
|
640
670
|
max_block_time_ms: Math.round(entry.maxBlockTimeMs),
|
|
641
671
|
max_handler_time_ms: Math.round(entry.maxHandlerTimeMs),
|
|
642
|
-
avg_ops_per_block: parseFloat(avgOpsPerBlock.toFixed(2)),
|
|
672
|
+
avg_ops_per_block: Number.parseFloat(avgOpsPerBlock.toFixed(2)),
|
|
643
673
|
is_catchup: entry.isCatchup
|
|
644
674
|
}).execute();
|
|
645
675
|
}
|
|
@@ -661,10 +691,14 @@ class StatsAccumulator {
|
|
|
661
691
|
}
|
|
662
692
|
|
|
663
693
|
// src/runtime/reindex.ts
|
|
694
|
+
import { getErrorMessage as getErrorMessage2 } from "@secondlayer/shared";
|
|
664
695
|
import { getDb as getDb2, getRawClient } from "@secondlayer/shared/db";
|
|
696
|
+
import {
|
|
697
|
+
recordGapBatch,
|
|
698
|
+
resolveGaps
|
|
699
|
+
} from "@secondlayer/shared/db/queries/subgraph-gaps";
|
|
665
700
|
import { updateSubgraphStatus as updateSubgraphStatus2 } from "@secondlayer/shared/db/queries/subgraphs";
|
|
666
701
|
import { logger as logger4 } from "@secondlayer/shared/logger";
|
|
667
|
-
import { getErrorMessage as getErrorMessage2 } from "@secondlayer/shared";
|
|
668
702
|
|
|
669
703
|
// src/schema/generator.ts
|
|
670
704
|
var TYPE_MAP = {
|
|
@@ -798,6 +832,28 @@ var LOG_INTERVAL = 1000;
|
|
|
798
832
|
var DEFAULT_BATCH_SIZE = 500;
|
|
799
833
|
var MIN_BATCH_SIZE = 100;
|
|
800
834
|
var MAX_BATCH_SIZE = 1000;
|
|
835
|
+
function coalesceFailedBlocks(blocks) {
|
|
836
|
+
if (blocks.length === 0)
|
|
837
|
+
return [];
|
|
838
|
+
blocks.sort((a, b) => a.height - b.height);
|
|
839
|
+
const ranges = [];
|
|
840
|
+
let start = blocks[0].height;
|
|
841
|
+
let end = blocks[0].height;
|
|
842
|
+
let reason = blocks[0].reason;
|
|
843
|
+
for (let i = 1;i < blocks.length; i++) {
|
|
844
|
+
const b = blocks[i];
|
|
845
|
+
if (b.height === end + 1 && b.reason === reason) {
|
|
846
|
+
end = b.height;
|
|
847
|
+
} else {
|
|
848
|
+
ranges.push({ start, end, reason });
|
|
849
|
+
start = b.height;
|
|
850
|
+
end = b.height;
|
|
851
|
+
reason = b.reason;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
ranges.push({ start, end, reason });
|
|
855
|
+
return ranges;
|
|
856
|
+
}
|
|
801
857
|
async function processBlockRange(def, opts) {
|
|
802
858
|
const db = getDb2();
|
|
803
859
|
const subgraphName = def.name;
|
|
@@ -818,9 +874,11 @@ async function processBlockRange(def, opts) {
|
|
|
818
874
|
const nextEnd = Math.min(nextStart + batchSize - 1, toBlock);
|
|
819
875
|
nextBatchPromise = loadBlockRange(db, nextStart, nextEnd);
|
|
820
876
|
}
|
|
877
|
+
const batchFailedBlocks = [];
|
|
821
878
|
for (let height = currentHeight;height <= batchEnd; height++) {
|
|
822
879
|
const blockData = batch.get(height);
|
|
823
880
|
if (!blockData) {
|
|
881
|
+
batchFailedBlocks.push({ height, reason: "block_missing" });
|
|
824
882
|
blocksProcessed++;
|
|
825
883
|
continue;
|
|
826
884
|
}
|
|
@@ -836,6 +894,7 @@ async function processBlockRange(def, opts) {
|
|
|
836
894
|
blockHeight: height,
|
|
837
895
|
error: err instanceof Error ? err.message : String(err)
|
|
838
896
|
});
|
|
897
|
+
batchFailedBlocks.push({ height, reason: "processing_error" });
|
|
839
898
|
await updateSubgraphStatus2(db, subgraphName, status, height).catch(() => {});
|
|
840
899
|
blocksProcessed++;
|
|
841
900
|
totalErrors++;
|
|
@@ -863,6 +922,15 @@ async function processBlockRange(def, opts) {
|
|
|
863
922
|
});
|
|
864
923
|
}
|
|
865
924
|
}
|
|
925
|
+
if (batchFailedBlocks.length > 0 && opts.subgraphId) {
|
|
926
|
+
const gaps = coalesceFailedBlocks(batchFailedBlocks);
|
|
927
|
+
await recordGapBatch(db, opts.subgraphId, subgraphName, gaps).catch((err) => {
|
|
928
|
+
logger4.warn("Failed to record subgraph gaps", {
|
|
929
|
+
subgraph: subgraphName,
|
|
930
|
+
error: err instanceof Error ? err.message : String(err)
|
|
931
|
+
});
|
|
932
|
+
});
|
|
933
|
+
}
|
|
866
934
|
const avg = avgEventsPerBlock(batch);
|
|
867
935
|
if (avg > 50)
|
|
868
936
|
batchSize = Math.max(Math.round(batchSize * 0.5), MIN_BATCH_SIZE);
|
|
@@ -900,28 +968,46 @@ async function reindexSubgraph(def, opts) {
|
|
|
900
968
|
logger4.info("Schema recreated for reindex", { subgraph: subgraphName });
|
|
901
969
|
const { fromBlock, toBlock } = await resolveBlockRange(db, opts);
|
|
902
970
|
if (fromBlock > toBlock) {
|
|
903
|
-
logger4.info("No blocks to reindex", {
|
|
971
|
+
logger4.info("No blocks to reindex", {
|
|
972
|
+
subgraph: subgraphName,
|
|
973
|
+
fromBlock,
|
|
974
|
+
toBlock
|
|
975
|
+
});
|
|
904
976
|
await updateSubgraphStatus2(db, subgraphName, "active", 0);
|
|
905
977
|
return { processed: 0 };
|
|
906
978
|
}
|
|
907
|
-
logger4.info("Reindexing blocks", {
|
|
908
|
-
|
|
979
|
+
logger4.info("Reindexing blocks", {
|
|
980
|
+
subgraph: subgraphName,
|
|
981
|
+
fromBlock,
|
|
982
|
+
toBlock,
|
|
983
|
+
totalBlocks: toBlock - fromBlock + 1
|
|
984
|
+
});
|
|
985
|
+
const subgraphRow = await db.selectFrom("subgraphs").select(["id", "api_key_id"]).where("name", "=", subgraphName).executeTakeFirst();
|
|
909
986
|
const result = await processBlockRange(def, {
|
|
910
987
|
fromBlock,
|
|
911
988
|
toBlock,
|
|
912
989
|
status: "reindexing",
|
|
913
990
|
isCatchup: false,
|
|
914
|
-
apiKeyId: subgraphRow?.api_key_id ?? null
|
|
991
|
+
apiKeyId: subgraphRow?.api_key_id ?? null,
|
|
992
|
+
subgraphId: subgraphRow?.id
|
|
915
993
|
});
|
|
916
994
|
const { recordSubgraphProcessed: recordSubgraphProcessed2 } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
917
995
|
if (result.totalEventsProcessed > 0 || result.totalErrors > 0) {
|
|
918
996
|
await recordSubgraphProcessed2(db, subgraphName, result.totalEventsProcessed, result.totalErrors, result.totalErrors > 0 ? `${result.totalErrors} error(s) during reindex` : undefined);
|
|
919
997
|
}
|
|
920
998
|
await updateSubgraphStatus2(db, subgraphName, "active", toBlock);
|
|
921
|
-
logger4.info("Reindex complete", {
|
|
999
|
+
logger4.info("Reindex complete", {
|
|
1000
|
+
subgraph: subgraphName,
|
|
1001
|
+
blocks: result.blocksProcessed,
|
|
1002
|
+
events: result.totalEventsProcessed,
|
|
1003
|
+
errors: result.totalErrors
|
|
1004
|
+
});
|
|
922
1005
|
return { processed: result.blocksProcessed };
|
|
923
1006
|
} catch (err) {
|
|
924
|
-
logger4.error("Reindex failed", {
|
|
1007
|
+
logger4.error("Reindex failed", {
|
|
1008
|
+
subgraph: subgraphName,
|
|
1009
|
+
error: getErrorMessage2(err)
|
|
1010
|
+
});
|
|
925
1011
|
await updateSubgraphStatus2(db, subgraphName, "error");
|
|
926
1012
|
throw err;
|
|
927
1013
|
}
|
|
@@ -929,24 +1015,44 @@ async function reindexSubgraph(def, opts) {
|
|
|
929
1015
|
async function backfillSubgraph(def, opts) {
|
|
930
1016
|
const db = getDb2();
|
|
931
1017
|
const subgraphName = def.name;
|
|
932
|
-
logger4.info("Backfill starting", {
|
|
1018
|
+
logger4.info("Backfill starting", {
|
|
1019
|
+
subgraph: subgraphName,
|
|
1020
|
+
from: opts.fromBlock,
|
|
1021
|
+
to: opts.toBlock
|
|
1022
|
+
});
|
|
933
1023
|
try {
|
|
934
|
-
const subgraphRow = await db.selectFrom("subgraphs").select("api_key_id").where("name", "=", subgraphName).executeTakeFirst();
|
|
1024
|
+
const subgraphRow = await db.selectFrom("subgraphs").select(["id", "api_key_id"]).where("name", "=", subgraphName).executeTakeFirst();
|
|
935
1025
|
const result = await processBlockRange(def, {
|
|
936
1026
|
fromBlock: opts.fromBlock,
|
|
937
1027
|
toBlock: opts.toBlock,
|
|
938
1028
|
status: "active",
|
|
939
1029
|
isCatchup: false,
|
|
940
|
-
apiKeyId: subgraphRow?.api_key_id ?? null
|
|
1030
|
+
apiKeyId: subgraphRow?.api_key_id ?? null,
|
|
1031
|
+
subgraphId: subgraphRow?.id
|
|
941
1032
|
});
|
|
1033
|
+
const resolved = await resolveGaps(db, subgraphName, opts.fromBlock, opts.toBlock).catch(() => 0);
|
|
1034
|
+
if (resolved > 0) {
|
|
1035
|
+
logger4.info("Resolved subgraph gaps via backfill", {
|
|
1036
|
+
subgraph: subgraphName,
|
|
1037
|
+
resolved
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
942
1040
|
const { recordSubgraphProcessed: recordSubgraphProcessed2 } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
943
1041
|
if (result.totalEventsProcessed > 0 || result.totalErrors > 0) {
|
|
944
1042
|
await recordSubgraphProcessed2(db, subgraphName, result.totalEventsProcessed, result.totalErrors, result.totalErrors > 0 ? `${result.totalErrors} error(s) during backfill` : undefined);
|
|
945
1043
|
}
|
|
946
|
-
logger4.info("Backfill complete", {
|
|
1044
|
+
logger4.info("Backfill complete", {
|
|
1045
|
+
subgraph: subgraphName,
|
|
1046
|
+
blocks: result.blocksProcessed,
|
|
1047
|
+
events: result.totalEventsProcessed,
|
|
1048
|
+
errors: result.totalErrors
|
|
1049
|
+
});
|
|
947
1050
|
return { processed: result.blocksProcessed };
|
|
948
1051
|
} catch (err) {
|
|
949
|
-
logger4.error("Backfill failed", {
|
|
1052
|
+
logger4.error("Backfill failed", {
|
|
1053
|
+
subgraph: subgraphName,
|
|
1054
|
+
error: getErrorMessage2(err)
|
|
1055
|
+
});
|
|
950
1056
|
throw err;
|
|
951
1057
|
}
|
|
952
1058
|
}
|
|
@@ -1008,7 +1114,13 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
1008
1114
|
const regData = {
|
|
1009
1115
|
name: def.name,
|
|
1010
1116
|
version: def.version || "1.0.0",
|
|
1011
|
-
definition: toJsonSafe({
|
|
1117
|
+
definition: toJsonSafe({
|
|
1118
|
+
name: def.name,
|
|
1119
|
+
version: def.version,
|
|
1120
|
+
description: def.description,
|
|
1121
|
+
sources: def.sources,
|
|
1122
|
+
schema: def.schema
|
|
1123
|
+
}),
|
|
1012
1124
|
schemaHash: hash,
|
|
1013
1125
|
handlerPath,
|
|
1014
1126
|
apiKeyId: opts?.apiKeyId,
|
|
@@ -1128,5 +1240,5 @@ export {
|
|
|
1128
1240
|
backfillSubgraph
|
|
1129
1241
|
};
|
|
1130
1242
|
|
|
1131
|
-
//# debugId=
|
|
1243
|
+
//# debugId=5A0D359BE0D619B264756E2164756E21
|
|
1132
1244
|
//# sourceMappingURL=index.js.map
|