From 33e4455f922e63110080b44638898def00e8e60c Mon Sep 17 00:00:00 2001 From: Nabarun Gogoi Date: Thu, 28 Dec 2023 15:07:12 +0530 Subject: [PATCH] Fix pruning of canonical block if null block is encountered (#499) --- .../src/templates/database-template.handlebars | 4 ++-- .../src/templates/indexer-template.handlebars | 4 ++-- packages/graph-node/test/utils/indexer.ts | 4 ++-- packages/util/src/database.ts | 12 +++++------- packages/util/src/indexer.ts | 4 ++-- packages/util/src/job-runner.ts | 12 ++++++++++-- packages/util/src/types.ts | 4 ++-- 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/codegen/src/templates/database-template.handlebars b/packages/codegen/src/templates/database-template.handlebars index 5fe2deab..31dc706c 100644 --- a/packages/codegen/src/templates/database-template.handlebars +++ b/packages/codegen/src/templates/database-template.handlebars @@ -324,8 +324,8 @@ export class Database implements DatabaseInterface { await this._baseDatabase.deleteEntitiesByConditions(queryRunner, entity, findConditions); } - async getAncestorAtDepth (blockHash: string, depth: number): Promise { - return this._baseDatabase.getAncestorAtDepth(blockHash, depth); + async getAncestorAtHeight (blockHash: string, height: number): Promise { + return this._baseDatabase.getAncestorAtHeight(blockHash, height); } _getPropertyColumnMapForEntity (entityName: string): Map { diff --git a/packages/codegen/src/templates/indexer-template.handlebars b/packages/codegen/src/templates/indexer-template.handlebars index 8bb78f23..306bb77f 100644 --- a/packages/codegen/src/templates/indexer-template.handlebars +++ b/packages/codegen/src/templates/indexer-template.handlebars @@ -744,8 +744,8 @@ export class Indexer implements IndexerInterface { return this._baseIndexer.updateBlockProgress(block, lastProcessedEventIndex); } - async getAncestorAtDepth (blockHash: string, depth: number): Promise { - return this._baseIndexer.getAncestorAtDepth(blockHash, depth); + async getAncestorAtHeight (blockHash: string, height: number): Promise { + return this._baseIndexer.getAncestorAtHeight(blockHash, height); } async resetWatcherToBlock (blockNumber: number): Promise { diff --git a/packages/graph-node/test/utils/indexer.ts b/packages/graph-node/test/utils/indexer.ts index 1aec8ee3..9f6a1a37 100644 --- a/packages/graph-node/test/utils/indexer.ts +++ b/packages/graph-node/test/utils/indexer.ts @@ -107,9 +107,9 @@ export class Indexer implements IndexerInterface { return []; } - async getAncestorAtDepth (blockHash: string, depth: number): Promise { + async getAncestorAtHeight (blockHash: string, height: number): Promise { assert(blockHash); - assert(depth); + assert(height); return ''; } diff --git a/packages/util/src/database.ts b/packages/util/src/database.ts index 4d67a022..e826667e 100644 --- a/packages/util/src/database.ts +++ b/packages/util/src/database.ts @@ -457,15 +457,14 @@ export class Database { await repo.delete(findConditions); } - async getAncestorAtDepth (blockHash: string, depth: number): Promise { + async getAncestorAtHeight (blockHash: string, height: number): Promise { const heirerchicalQuery = ` WITH RECURSIVE cte_query AS ( SELECT block_hash, block_number, - parent_hash, - 0 as depth + parent_hash FROM block_progress WHERE @@ -474,14 +473,13 @@ export class Database { SELECT b.block_hash, b.block_number, - b.parent_hash, - c.depth + 1 + b.parent_hash FROM block_progress b INNER JOIN cte_query c ON c.parent_hash = b.block_hash WHERE - c.depth < $2 + b.block_number >= $2 ) SELECT block_hash, block_number @@ -492,7 +490,7 @@ export class Database { `; // Get ancestor block hash using heirarchical query. - const [{ block_hash: ancestorBlockHash }] = await this._conn.query(heirerchicalQuery, [blockHash, depth]); + const [{ block_hash: ancestorBlockHash }] = await this._conn.query(heirerchicalQuery, [blockHash, height]); return ancestorBlockHash; } diff --git a/packages/util/src/indexer.ts b/packages/util/src/indexer.ts index 292def97..55473436 100644 --- a/packages/util/src/indexer.ts +++ b/packages/util/src/indexer.ts @@ -713,8 +713,8 @@ export class Indexer { } } - async getAncestorAtDepth (blockHash: string, depth: number): Promise { - return this._db.getAncestorAtDepth(blockHash, depth); + async getAncestorAtHeight (blockHash: string, height: number): Promise { + return this._db.getAncestorAtHeight(blockHash, height); } async saveEventEntity (dbEvent: EventInterface): Promise { diff --git a/packages/util/src/job-runner.ts b/packages/util/src/job-runner.ts index 163fd2cd..05ed6994 100644 --- a/packages/util/src/job-runner.ts +++ b/packages/util/src/job-runner.ts @@ -445,10 +445,18 @@ export class JobRunner { // We have more than one node at this height, so prune all nodes not reachable from indexed block at max reorg depth from prune height. // This will lead to orphaned nodes, which will get pruned at the next height. if (blocksAtHeight.length > 1) { - const [indexedBlock] = await this._indexer.getBlocksAtHeight(pruneBlockHeight + MAX_REORG_DEPTH, false); + let indexedBlock: BlockProgressInterface | undefined; + let indexedBlockHeight = pruneBlockHeight + MAX_REORG_DEPTH; + + // Loop to find latest indexed block incase null block is encountered + while (!indexedBlock) { + [indexedBlock] = await this._indexer.getBlocksAtHeight(indexedBlockHeight, false); + --indexedBlockHeight; + assert(indexedBlockHeight > pruneBlockHeight, `No blocks found above pruneBlockHeight ${pruneBlockHeight}`); + } // Get ancestor blockHash from indexed block at prune height. - const ancestorBlockHash = await this._indexer.getAncestorAtDepth(indexedBlock.blockHash, MAX_REORG_DEPTH); + const ancestorBlockHash = await this._indexer.getAncestorAtHeight(indexedBlock.blockHash, pruneBlockHeight); newCanonicalBlockHash = ancestorBlockHash; const blocksToBePruned = blocksAtHeight.filter(block => ancestorBlockHash !== block.blockHash); diff --git a/packages/util/src/types.ts b/packages/util/src/types.ts index 0af2b4bc..78ae88cc 100644 --- a/packages/util/src/types.ts +++ b/packages/util/src/types.ts @@ -173,7 +173,7 @@ export interface IndexerInterface { getLatestCanonicalBlock (): Promise getLatestStateIndexedBlock (): Promise getBlockEvents (blockHash: string, where: Where, queryOptions: QueryOptions): Promise> - getAncestorAtDepth (blockHash: string, depth: number): Promise + getAncestorAtHeight (blockHash: string, height: number): Promise saveBlockAndFetchEvents (block: DeepPartial): Promise<[ BlockProgressInterface, DeepPartial[], @@ -249,7 +249,7 @@ export interface DatabaseInterface { getBlockEvents (blockHash: string, where?: Where, queryOptions?: QueryOptions): Promise; getEvent (id: string): Promise getSyncStatus (queryRunner: QueryRunner): Promise - getAncestorAtDepth (blockHash: string, depth: number): Promise + getAncestorAtHeight (blockHash: string, height: number): Promise getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }>; getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise>; markBlocksAsPruned (queryRunner: QueryRunner, blocks: BlockProgressInterface[]): Promise;