@subql/node-ethereum 6.3.4-1 → 6.4.0-2

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.
@@ -2,17 +2,16 @@ import { UnfinalizedBlocksService as BaseUnfinalizedBlocksService, Header, NodeC
2
2
  import { BlockchainService } from '../blockchain.service';
3
3
  import { BlockContent } from './types';
4
4
  export declare class UnfinalizedBlocksService extends BaseUnfinalizedBlocksService<BlockContent> {
5
- private supportsFinalization?;
6
5
  private startupCheck;
7
6
  constructor(nodeConfig: NodeConfig, storeModelProvider: IStoreModelProvider, blockchainService: BlockchainService);
8
7
  /**
9
8
  * @param reindex - the function to reindex back before a fork
10
- * @param supportsFinalization - If the chain supports the 'finalized' block tag this should be true.
11
9
  * */
12
- init(reindex: (targetHeight: Header) => Promise<void>, supportsFinalisation?: boolean): Promise<Header | undefined>;
10
+ init(reindex: (targetHeight: Header) => Promise<void>): Promise<Header | undefined>;
13
11
  /**
14
- * Checks if a fork has happened, this doesn't find the start of the fork just where it was detected
15
- * @returns (Header | undefined) - The header may be the forked header but will most likely be the main header. Either way it should be used just for the block height
12
+ * Checks if a fork has happened during startup by verifying the last unfinalized block hash.
13
+ * Runtime fork detection is handled by node-core's registerUnfinalizedBlock which validates parentHash chain.
14
+ * @returns (Header | undefined) - The header if fork is detected at startup
16
15
  * */
17
16
  protected hasForked(): Promise<Header | undefined>;
18
17
  /**
@@ -22,7 +22,6 @@ const blockchain_service_1 = require("../blockchain.service");
22
22
  const NodeConfig_1 = require("../configure/NodeConfig");
23
23
  const logger = (0, node_core_1.getLogger)('UnfinalizedBlocksService');
24
24
  let UnfinalizedBlocksService = class UnfinalizedBlocksService extends node_core_1.UnfinalizedBlocksService {
25
- supportsFinalization;
26
25
  startupCheck = true;
27
26
  constructor(nodeConfig, storeModelProvider, blockchainService) {
28
27
  // blockchain service cast is due to unsolvable typescript generic error, it wokrs on the main sdk but not here
@@ -30,22 +29,18 @@ let UnfinalizedBlocksService = class UnfinalizedBlocksService extends node_core_
30
29
  }
31
30
  /**
32
31
  * @param reindex - the function to reindex back before a fork
33
- * @param supportsFinalization - If the chain supports the 'finalized' block tag this should be true.
34
32
  * */
35
33
  // eslint-disable-next-line @typescript-eslint/require-await
36
- async init(reindex, supportsFinalisation) {
37
- this.supportsFinalization = supportsFinalisation;
34
+ async init(reindex) {
38
35
  return super.init(reindex);
39
36
  }
40
37
  /**
41
- * Checks if a fork has happened, this doesn't find the start of the fork just where it was detected
42
- * @returns (Header | undefined) - The header may be the forked header but will most likely be the main header. Either way it should be used just for the block height
38
+ * Checks if a fork has happened during startup by verifying the last unfinalized block hash.
39
+ * Runtime fork detection is handled by node-core's registerUnfinalizedBlock which validates parentHash chain.
40
+ * @returns (Header | undefined) - The header if fork is detected at startup
43
41
  * */
44
42
  async hasForked() {
45
- if (this.supportsFinalization) {
46
- return super.hasForked();
47
- }
48
- // Startup check helps speed up finding a fork by checking the hash of the last unfinalized block
43
+ // Startup check verifies the last unfinalized block hash against the chain
49
44
  if (this.startupCheck) {
50
45
  this.startupCheck = false;
51
46
  const lastUnfinalized = (0, lodash_1.last)(this.unfinalizedBlocks);
@@ -62,6 +57,7 @@ let UnfinalizedBlocksService = class UnfinalizedBlocksService extends node_core_
62
57
  const i = this.unfinalizedBlocks.length - 1;
63
58
  const current = this.unfinalizedBlocks[i];
64
59
  const parent = this.unfinalizedBlocks[i - 1];
60
+ // this now won't find fork as such cases has been covered when registerUnfinalizedBlock() is called
65
61
  if (current.parentHash !== parent.blockHash) {
66
62
  // We've found a fork now we need to find where the fork happened
67
63
  logger.warn(`Block fork detected at ${current.blockHeight}. Parent hash ${current.parentHash} doesn't match indexed parent ${parent.blockHash}.`);
@@ -74,9 +70,6 @@ let UnfinalizedBlocksService = class UnfinalizedBlocksService extends node_core_
74
70
  * @return (number | undefined) - The block height to rewind to to remove forked data
75
71
  **/
76
72
  async getLastCorrectFinalizedBlock(forkedHeader) {
77
- if (this.supportsFinalization) {
78
- return super.getLastCorrectFinalizedBlock(forkedHeader);
79
- }
80
73
  const bestVerifiableBlocks = this.unfinalizedBlocks.filter(({ blockHeight }) => blockHeight < forkedHeader.blockHeight);
81
74
  let checkingHeader = forkedHeader;
82
75
  // Work backwards through the blocks until we find a matching hash
@@ -1 +1 @@
1
- {"version":3,"file":"unfinalizedBlocks.service.js","sourceRoot":"","sources":["../../src/indexer/unfinalizedBlocks.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Inject, Injectable } from '@nestjs/common';\nimport {\n UnfinalizedBlocksService as BaseUnfinalizedBlocksService,\n Header,\n NodeConfig,\n getLogger,\n profiler,\n POI_NOT_ENABLED_ERROR_MESSAGE,\n IStoreModelProvider,\n IBlockchainService,\n} from '@subql/node-core';\nimport { last } from 'lodash';\nimport { BlockchainService } from '../blockchain.service';\nimport { EthereumNodeConfig } from '../configure/NodeConfig';\nimport { BlockContent } from './types';\n\nconst logger = getLogger('UnfinalizedBlocksService');\n\n@Injectable()\nexport class UnfinalizedBlocksService extends BaseUnfinalizedBlocksService<BlockContent> {\n private supportsFinalization?: boolean;\n private startupCheck = true;\n\n constructor(\n nodeConfig: NodeConfig,\n @Inject('IStoreModelProvider') storeModelProvider: IStoreModelProvider,\n @Inject('IBlockchainService') blockchainService: BlockchainService,\n ) {\n // blockchain service cast is due to unsolvable typescript generic error, it wokrs on the main sdk but not here\n super(\n new EthereumNodeConfig(nodeConfig),\n storeModelProvider,\n blockchainService as IBlockchainService,\n );\n }\n\n /**\n * @param reindex - the function to reindex back before a fork\n * @param supportsFinalization - If the chain supports the 'finalized' block tag this should be true.\n * */\n // eslint-disable-next-line @typescript-eslint/require-await\n async init(\n reindex: (targetHeight: Header) => Promise<void>,\n supportsFinalisation?: boolean,\n ): Promise<Header | undefined> {\n this.supportsFinalization = supportsFinalisation;\n return super.init(reindex);\n }\n /**\n * Checks if a fork has happened, this doesn't find the start of the fork just where it was detected\n * @returns (Header | undefined) - The header may be the forked header but will most likely be the main header. Either way it should be used just for the block height\n * */\n @profiler()\n protected async hasForked(): Promise<Header | undefined> {\n if (this.supportsFinalization) {\n return super.hasForked();\n }\n\n // Startup check helps speed up finding a fork by checking the hash of the last unfinalized block\n if (this.startupCheck) {\n this.startupCheck = false;\n const lastUnfinalized = last(this.unfinalizedBlocks);\n if (lastUnfinalized) {\n const checkUnfinalized =\n await this.blockchainService.getHeaderForHeight(\n lastUnfinalized.blockHeight,\n );\n\n if (lastUnfinalized.blockHash !== checkUnfinalized.blockHash) {\n return checkUnfinalized;\n }\n }\n }\n\n if (this.unfinalizedBlocks.length <= 2) {\n return;\n }\n\n const i = this.unfinalizedBlocks.length - 1;\n const current = this.unfinalizedBlocks[i];\n const parent = this.unfinalizedBlocks[i - 1];\n\n if (current.parentHash !== parent.blockHash) {\n // We've found a fork now we need to find where the fork happened\n logger.warn(\n `Block fork detected at ${current.blockHeight}. Parent hash ${current.parentHash} doesn't match indexed parent ${parent.blockHash}.`,\n );\n\n return current;\n }\n\n return;\n }\n\n /**\n * Finds the height before the fork occurred based on the result of hasForked\n * @return (number | undefined) - The block height to rewind to to remove forked data\n **/\n protected async getLastCorrectFinalizedBlock(\n forkedHeader: Header,\n ): Promise<Header | undefined> {\n if (this.supportsFinalization) {\n return super.getLastCorrectFinalizedBlock(forkedHeader);\n }\n\n const bestVerifiableBlocks = this.unfinalizedBlocks.filter(\n ({ blockHeight }) => blockHeight < forkedHeader.blockHeight,\n );\n\n let checkingHeader = forkedHeader;\n\n // Work backwards through the blocks until we find a matching hash\n for (const header of bestVerifiableBlocks.reverse()) {\n if (\n header.blockHash === checkingHeader.blockHash ||\n header.blockHash === checkingHeader.parentHash\n ) {\n return header;\n }\n\n // Get the new parent\n if (!checkingHeader.parentHash) {\n throw new Error('Unable to get parent hash for header');\n }\n const parentHeight = checkingHeader.blockHeight - 1;\n try {\n checkingHeader = await this.blockchainService.getHeaderForHash(\n checkingHeader.parentHash,\n );\n } catch {\n // Parent block not found on chain (orphaned), fall back to height-based check\n logger.warn(\n `Failed to get block by hash, falling back to height-based check at height ${parentHeight}`,\n );\n checkingHeader = await this.blockchainService.getHeaderForHeight(\n parentHeight,\n );\n }\n }\n\n try {\n const poiHeader = await this.findFinalizedUsingPOI(checkingHeader);\n return poiHeader;\n } catch (e: any) {\n if (e.message === POI_NOT_ENABLED_ERROR_MESSAGE) {\n return this.blockchainService.getHeaderForHeight(\n Math.max(\n 0,\n forkedHeader.blockHeight -\n (this.nodeConfig as EthereumNodeConfig).blockForkReindex,\n ),\n );\n }\n // TODO rewind back 1000+ blocks\n logger.info('Failed to use POI to rewind block');\n throw e;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"unfinalizedBlocks.service.js","sourceRoot":"","sources":["../../src/indexer/unfinalizedBlocks.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Inject, Injectable } from '@nestjs/common';\nimport {\n UnfinalizedBlocksService as BaseUnfinalizedBlocksService,\n Header,\n NodeConfig,\n getLogger,\n profiler,\n POI_NOT_ENABLED_ERROR_MESSAGE,\n IStoreModelProvider,\n IBlockchainService,\n} from '@subql/node-core';\nimport { last } from 'lodash';\nimport { BlockchainService } from '../blockchain.service';\nimport { EthereumNodeConfig } from '../configure/NodeConfig';\nimport { BlockContent } from './types';\n\nconst logger = getLogger('UnfinalizedBlocksService');\n\n@Injectable()\nexport class UnfinalizedBlocksService extends BaseUnfinalizedBlocksService<BlockContent> {\n private startupCheck = true;\n\n constructor(\n nodeConfig: NodeConfig,\n @Inject('IStoreModelProvider') storeModelProvider: IStoreModelProvider,\n @Inject('IBlockchainService') blockchainService: BlockchainService,\n ) {\n // blockchain service cast is due to unsolvable typescript generic error, it wokrs on the main sdk but not here\n super(\n new EthereumNodeConfig(nodeConfig),\n storeModelProvider,\n blockchainService as IBlockchainService,\n );\n }\n\n /**\n * @param reindex - the function to reindex back before a fork\n * */\n // eslint-disable-next-line @typescript-eslint/require-await\n async init(\n reindex: (targetHeight: Header) => Promise<void>,\n ): Promise<Header | undefined> {\n return super.init(reindex);\n }\n\n /**\n * Checks if a fork has happened during startup by verifying the last unfinalized block hash.\n * Runtime fork detection is handled by node-core's registerUnfinalizedBlock which validates parentHash chain.\n * @returns (Header | undefined) - The header if fork is detected at startup\n * */\n @profiler()\n protected async hasForked(): Promise<Header | undefined> {\n // Startup check verifies the last unfinalized block hash against the chain\n if (this.startupCheck) {\n this.startupCheck = false;\n const lastUnfinalized = last(this.unfinalizedBlocks);\n if (lastUnfinalized) {\n const checkUnfinalized =\n await this.blockchainService.getHeaderForHeight(\n lastUnfinalized.blockHeight,\n );\n\n if (lastUnfinalized.blockHash !== checkUnfinalized.blockHash) {\n return checkUnfinalized;\n }\n }\n }\n\n if (this.unfinalizedBlocks.length <= 2) {\n return;\n }\n\n const i = this.unfinalizedBlocks.length - 1;\n const current = this.unfinalizedBlocks[i];\n const parent = this.unfinalizedBlocks[i - 1];\n\n // this now won't find fork as such cases has been covered when registerUnfinalizedBlock() is called\n if (current.parentHash !== parent.blockHash) {\n // We've found a fork now we need to find where the fork happened\n logger.warn(\n `Block fork detected at ${current.blockHeight}. Parent hash ${current.parentHash} doesn't match indexed parent ${parent.blockHash}.`,\n );\n\n return current;\n }\n\n return;\n }\n\n /**\n * Finds the height before the fork occurred based on the result of hasForked\n * @return (number | undefined) - The block height to rewind to to remove forked data\n **/\n protected async getLastCorrectFinalizedBlock(\n forkedHeader: Header,\n ): Promise<Header | undefined> {\n const bestVerifiableBlocks = this.unfinalizedBlocks.filter(\n ({ blockHeight }) => blockHeight < forkedHeader.blockHeight,\n );\n\n let checkingHeader = forkedHeader;\n\n // Work backwards through the blocks until we find a matching hash\n for (const header of bestVerifiableBlocks.reverse()) {\n if (\n header.blockHash === checkingHeader.blockHash ||\n header.blockHash === checkingHeader.parentHash\n ) {\n return header;\n }\n\n // Get the new parent\n if (!checkingHeader.parentHash) {\n throw new Error('Unable to get parent hash for header');\n }\n const parentHeight = checkingHeader.blockHeight - 1;\n try {\n checkingHeader = await this.blockchainService.getHeaderForHash(\n checkingHeader.parentHash,\n );\n } catch {\n // Parent block not found on chain (orphaned), fall back to height-based check\n logger.warn(\n `Failed to get block by hash, falling back to height-based check at height ${parentHeight}`,\n );\n checkingHeader = await this.blockchainService.getHeaderForHeight(\n parentHeight,\n );\n }\n }\n\n try {\n const poiHeader = await this.findFinalizedUsingPOI(checkingHeader);\n return poiHeader;\n } catch (e: any) {\n if (e.message === POI_NOT_ENABLED_ERROR_MESSAGE) {\n return this.blockchainService.getHeaderForHeight(\n Math.max(\n 0,\n forkedHeader.blockHeight -\n (this.nodeConfig as EthereumNodeConfig).blockForkReindex,\n ),\n );\n }\n // TODO rewind back 1000+ blocks\n logger.info('Failed to use POI to rewind block');\n throw e;\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subql/node-ethereum",
3
- "version": "6.3.4-1",
3
+ "version": "6.4.0-2",
4
4
  "description": "",
5
5
  "author": "Ian He",
6
6
  "license": "GPL-3.0",
@@ -26,7 +26,7 @@
26
26
  "@nestjs/schedule": "^5.0.1",
27
27
  "@subql/common": "^5.8.2",
28
28
  "@subql/common-ethereum": "4.10.1",
29
- "@subql/node-core": "^19.1.0",
29
+ "@subql/node-core": "^19.2.0",
30
30
  "@subql/testing": "^2.2.1",
31
31
  "@subql/types-ethereum": "4.2.3",
32
32
  "cacheable-lookup": "6",
@@ -70,5 +70,5 @@
70
70
  "CHANGELOG.md",
71
71
  "LICENSE"
72
72
  ],
73
- "stableVersion": "6.3.4-0"
73
+ "stableVersion": "6.4.0-1"
74
74
  }