@subql/node 6.4.5-0 → 6.4.6-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.
@@ -25,7 +25,6 @@ const types_2 = require("./indexer/types");
25
25
  const substrate_1 = require("./utils/substrate");
26
26
  const BLOCK_TIME_VARIANCE = 5000; //ms
27
27
  const INTERVAL_PERCENT = 0.9;
28
- // eslint-disable-next-line @typescript-eslint/no-var-requires
29
28
  const { version: packageVersion } = require('../package.json');
30
29
  let BlockchainService = class BlockchainService {
31
30
  apiService;
@@ -51,7 +50,6 @@ let BlockchainService = class BlockchainService {
51
50
  if (syncedDictionary) {
52
51
  context.workers.map((w) => w.syncRuntimeService(this.runtimeService.specVersionMap, this.runtimeService.latestFinalizedHeight));
53
52
  }
54
- // const start = new Date();
55
53
  return worker.fetchBlock(height, blockSpecVersion);
56
54
  }
57
55
  async onProjectChange(project) {
@@ -1 +1 @@
1
- {"version":3,"file":"blockchain.service.js","sourceRoot":"","sources":["../src/blockchain.service.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;;;;;;;;;;;;;;AAEnC,2CAAoD;AACpD,8DAAkE;AAClE,gDAM0B;AAC1B,wCAMsB;AAKtB,uDAAmD;AACnD,qEAAkE;AAClE,2CAMyB;AAEzB,iDAK2B;AAE3B,MAAM,mBAAmB,GAAG,IAAI,CAAC,CAAC,IAAI;AACtC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B,8DAA8D;AAC9D,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAGxD,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAgBI;IACI;IAFpC,YACgC,UAAsB,EAClB,cAA8B;QADlC,eAAU,GAAV,UAAU,CAAY;QAClB,mBAAc,GAAd,cAAc,CAAgB;IAC/D,CAAC;IAEJ,UAAU,GAAG,6BAAU,CAAC;IACxB,WAAW,GAAG,8BAAW,CAAC;IAC1B,gBAAgB,GAAG,4BAAoB,CAAC,KAAK,CAAC;IAC9C,cAAc,GAAG,cAAc,CAAC;IAG1B,AAAN,KAAK,CAAC,WAAW,CACf,SAAmB;QAEnB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,WAAW,CACvD,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAChC,CAAC;QAEF,qEAAqE;QACrE,sCAAsC;QACtC,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,CAChC,SAAS,EACT,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAChE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,MAAsB,EACtB,MAAc,EACd,OAAsC;QAEtC,4CAA4C;QAC5C,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GAC1C,MAAM,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAEnD,mHAAmH;QACnH,IAAI,gBAAgB,EAAE,CAAC;YACrB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACxB,CAAC,CAAC,kBAAkB,CAClB,IAAI,CAAC,cAAc,CAAC,cAAc,EAClC,IAAI,CAAC,cAAc,CAAC,qBAAqB,CAC1C,CACF,CAAC;QACJ,CAAC;QAED,4BAA4B;QAC5B,OAAO,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,OAAwB;QAC5C,iDAAiD;QACjD,MAAM,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,CAAC;QACzC,IAAI,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,MAAc;QACpC,MAAM,KAAK,GAAG,MAAM,IAAA,4BAAgB,EAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAElE,IAAI,SAAS,GAAG,IAAA,wBAAY,EAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,uDAAuD;YACvD,MAAM,cAAc,GAAG,MAAM,CAC3B,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAC/C,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;YAExB,SAAS,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,YAAY,CAAC,KAAa;QACxB,OAAO,IAAA,oBAAY,EAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,MAAM,aAAa,GACjB,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;QAE/D,OAAO,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACzE,OAAO,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IACtC,CAAC;IACD,4DAA4D;IAC5D,KAAK,CAAC,gBAAgB;QACpB,MAAM,aAAa,GAAG,IAAA,wBAAY,EAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;aAC1D,IAAI,CAAC,gBAAgB,CAAC;aACtB,QAAQ,EAAE,CAAC;QAEd,OAAO,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAC;IACtD,CAAC;IAED,2DAA2D;IAErD,AAAN,KAAK,CAAC,gBAAgB,CAAC,IAAY;QACjC,OAAO,IAAA,4BAAgB,EAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3D,CAAC;IAED,2DAA2D;IAErD,AAAN,KAAK,CAAC,kBAAkB,CAAC,MAAc;QACrC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,4DAA4D;IAC5D,KAAK,CAAC,eAAe,CACnB,MAAwB,EACxB,KAAyB;QAEzB,IAAI,IAAA,6BAAU,EAAC,KAAK,CAAC,EAAE,CAAC;YACtB,KAAK,CAAC,SAAS,CAAC,OAAO,GAAG;gBACxB,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO;gBAC1B,GAAG,MAAM,CAAC,IAAI;aACf,CAAC;YACF,gCAAgC;YAChC,2DAA2D;QAC7D,CAAC;aAAM,IAAI,IAAA,8BAAW,EAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,2CAA2C;QAC7C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAuC;QACtD,MAAM,cAAc,GAAG,CAAC,IAAA,mBAAW,EAAC,KAAK,CAAC;YACxC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAE7D,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAClC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EACxB,cAAc,CACf,CAAC;IACJ,CAAC;CACF,CAAA;AAtJY,8CAAiB;AA0BtB;IADL,IAAA,0BAAc,GAAE;;;;oDAchB;AAyEK;IADL,IAAA,0BAAc,GAAE;;;;yDAGhB;AAIK;IADL,IAAA,0BAAc,GAAE;;;;2DAIhB;4BAzHU,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;IAiBR,WAAA,IAAA,eAAM,EAAC,YAAY,CAAC,CAAA;IACpB,WAAA,IAAA,eAAM,EAAC,gBAAgB,CAAC,CAAA;qCADiB,wBAAU;QACF,+BAAc;GAjBvD,iBAAiB,CAsJ7B","sourcesContent":["// Copyright 2020-2025 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Inject, Injectable } from '@nestjs/common';\nimport { isCustomDs, isRuntimeDs } from '@subql/common-substrate';\nimport {\n DatasourceParams,\n Header,\n IBlock,\n IBlockchainService,\n mainThreadOnly,\n} from '@subql/node-core';\nimport {\n SubstrateCustomDatasource,\n SubstrateCustomHandler,\n SubstrateDatasource,\n SubstrateHandlerKind,\n SubstrateMapping,\n} from '@subql/types';\nimport {\n SubqueryProject,\n SubstrateProjectDs,\n} from './configure/SubqueryProject';\nimport { ApiService } from './indexer/api.service';\nimport { RuntimeService } from './indexer/runtime/runtimeService';\nimport {\n ApiAt,\n BlockContent,\n getBlockSize,\n isFullBlock,\n LightBlockContent,\n} from './indexer/types';\nimport { IIndexerWorker } from './indexer/worker/worker';\nimport {\n calcInterval,\n getBlockByHeight,\n getTimestamp,\n getHeaderForHash,\n} from './utils/substrate';\n\nconst BLOCK_TIME_VARIANCE = 5000; //ms\nconst INTERVAL_PERCENT = 0.9;\n\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { version: packageVersion } = require('../package.json');\n\n@Injectable()\nexport class BlockchainService\n implements\n IBlockchainService<\n SubstrateDatasource,\n SubstrateCustomDatasource<\n string,\n SubstrateMapping<SubstrateCustomHandler>\n >,\n SubqueryProject,\n ApiAt,\n LightBlockContent,\n BlockContent,\n IIndexerWorker\n >\n{\n constructor(\n @Inject('APIService') private apiService: ApiService,\n @Inject('RuntimeService') private runtimeService: RuntimeService,\n ) {}\n\n isCustomDs = isCustomDs;\n isRuntimeDs = isRuntimeDs;\n blockHandlerKind = SubstrateHandlerKind.Block;\n packageVersion = packageVersion;\n\n @mainThreadOnly()\n async fetchBlocks(\n blockNums: number[],\n ): Promise<IBlock<BlockContent>[] | IBlock<LightBlockContent>[]> {\n const specChanged = await this.runtimeService.specChanged(\n blockNums[blockNums.length - 1],\n );\n\n // If specVersion not changed, a known overallSpecVer will be pass in\n // Otherwise use api to fetch runtimes\n return this.apiService.fetchBlocks(\n blockNums,\n specChanged ? undefined : this.runtimeService.parentSpecVersion,\n );\n }\n\n async fetchBlockWorker(\n worker: IIndexerWorker,\n height: number,\n context: { workers: IIndexerWorker[] },\n ): Promise<Header> {\n // get SpecVersion from main runtime service\n const { blockSpecVersion, syncedDictionary } =\n await this.runtimeService.getSpecVersion(height);\n\n // if main runtime specVersion has been updated, then sync with all workers specVersion map, and lastFinalizedBlock\n if (syncedDictionary) {\n context.workers.map((w) =>\n w.syncRuntimeService(\n this.runtimeService.specVersionMap,\n this.runtimeService.latestFinalizedHeight,\n ),\n );\n }\n\n // const start = new Date();\n return worker.fetchBlock(height, blockSpecVersion);\n }\n\n async onProjectChange(project: SubqueryProject): Promise<void> {\n // Only network with chainTypes require to reload\n await this.apiService.updateChainTypes();\n this.apiService.updateBlockFetching();\n }\n\n async getBlockTimestamp(height: number): Promise<Date> {\n const block = await getBlockByHeight(this.apiService.api, height);\n\n let timestamp = getTimestamp(block);\n if (!timestamp) {\n // Not all networks have a block timestamp, e.g. Shiden\n const blockTimestamp = await (\n await this.apiService.unsafeApi.at(block.hash)\n ).query.timestamp.now();\n\n timestamp = new Date(blockTimestamp.toNumber());\n }\n\n return timestamp;\n }\n\n getBlockSize(block: IBlock): number {\n return getBlockSize(block);\n }\n\n async getFinalizedHeader(): Promise<Header> {\n const finalizedHash =\n await this.apiService.unsafeApi.rpc.chain.getFinalizedHead();\n\n return this.getHeaderForHash(finalizedHash.toHex());\n }\n\n async getBestHeight(): Promise<number> {\n const bestHeader = await this.apiService.unsafeApi.rpc.chain.getHeader();\n return bestHeader.number.toNumber();\n }\n // eslint-disable-next-line @typescript-eslint/require-await\n async getChainInterval(): Promise<number> {\n const chainInterval = calcInterval(this.apiService.unsafeApi)\n .muln(INTERVAL_PERCENT)\n .toNumber();\n\n return Math.min(BLOCK_TIME_VARIANCE, chainInterval);\n }\n\n // TODO can this decorator be in unfinalizedBlocks Service?\n @mainThreadOnly()\n async getHeaderForHash(hash: string): Promise<Header> {\n return getHeaderForHash(this.apiService.unsafeApi, hash);\n }\n\n // TODO can this decorator be in unfinalizedBlocks Service?\n @mainThreadOnly()\n async getHeaderForHeight(height: number): Promise<Header> {\n const hash = await this.apiService.unsafeApi.rpc.chain.getBlockHash(height);\n return this.getHeaderForHash(hash.toHex());\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async updateDynamicDs(\n params: DatasourceParams,\n dsObj: SubstrateProjectDs,\n ): Promise<void> {\n if (isCustomDs(dsObj)) {\n dsObj.processor.options = {\n ...dsObj.processor.options,\n ...params.args,\n };\n // TODO needs dsProcessorService\n // await this.dsProcessorService.validateCustomDs([dsObj]);\n } else if (isRuntimeDs(dsObj)) {\n // XXX add any modifications to the ds here\n }\n }\n\n async getSafeApi(block: LightBlockContent | BlockContent): Promise<ApiAt> {\n const runtimeVersion = !isFullBlock(block)\n ? undefined\n : await this.runtimeService.getRuntimeVersion(block.block);\n\n return this.apiService.getPatchedApi(\n block.block.block.header,\n runtimeVersion,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"blockchain.service.js","sourceRoot":"","sources":["../src/blockchain.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 { isCustomDs, isRuntimeDs } from '@subql/common-substrate';\nimport {\n DatasourceParams,\n Header,\n IBlock,\n IBlockchainService,\n mainThreadOnly,\n} from '@subql/node-core';\nimport {\n SubstrateCustomDatasource,\n SubstrateCustomHandler,\n SubstrateDatasource,\n SubstrateHandlerKind,\n SubstrateMapping,\n} from '@subql/types';\nimport {\n SubqueryProject,\n SubstrateProjectDs,\n} from './configure/SubqueryProject';\nimport { ApiService } from './indexer/api.service';\nimport { RuntimeService } from './indexer/runtime/runtimeService';\nimport {\n ApiAt,\n BlockContent,\n getBlockSize,\n isFullBlock,\n LightBlockContent,\n} from './indexer/types';\nimport { IIndexerWorker } from './indexer/worker/worker';\nimport {\n calcInterval,\n getBlockByHeight,\n getTimestamp,\n getHeaderForHash,\n} from './utils/substrate';\n\nconst BLOCK_TIME_VARIANCE = 5000; //ms\nconst INTERVAL_PERCENT = 0.9;\n\nconst { version: packageVersion } = require('../package.json');\n\n@Injectable()\nexport class BlockchainService\n implements\n IBlockchainService<\n SubstrateDatasource,\n SubstrateCustomDatasource<\n string,\n SubstrateMapping<SubstrateCustomHandler>\n >,\n SubqueryProject,\n ApiAt,\n LightBlockContent,\n BlockContent,\n IIndexerWorker\n >\n{\n constructor(\n @Inject('APIService') private apiService: ApiService,\n @Inject('RuntimeService') private runtimeService: RuntimeService,\n ) {}\n\n isCustomDs = isCustomDs;\n isRuntimeDs = isRuntimeDs;\n blockHandlerKind = SubstrateHandlerKind.Block;\n packageVersion = packageVersion;\n\n @mainThreadOnly()\n async fetchBlocks(\n blockNums: number[],\n ): Promise<IBlock<BlockContent>[] | IBlock<LightBlockContent>[]> {\n const specChanged = await this.runtimeService.specChanged(\n blockNums[blockNums.length - 1],\n );\n\n // If specVersion not changed, a known overallSpecVer will be pass in\n // Otherwise use api to fetch runtimes\n return this.apiService.fetchBlocks(\n blockNums,\n specChanged ? undefined : this.runtimeService.parentSpecVersion,\n );\n }\n\n async fetchBlockWorker(\n worker: IIndexerWorker,\n height: number,\n context: { workers: IIndexerWorker[] },\n ): Promise<Header> {\n // get SpecVersion from main runtime service\n const { blockSpecVersion, syncedDictionary } =\n await this.runtimeService.getSpecVersion(height);\n\n // if main runtime specVersion has been updated, then sync with all workers specVersion map, and lastFinalizedBlock\n if (syncedDictionary) {\n context.workers.map((w) =>\n w.syncRuntimeService(\n this.runtimeService.specVersionMap,\n this.runtimeService.latestFinalizedHeight,\n ),\n );\n }\n\n return worker.fetchBlock(height, blockSpecVersion);\n }\n\n async onProjectChange(project: SubqueryProject): Promise<void> {\n // Only network with chainTypes require to reload\n await this.apiService.updateChainTypes();\n this.apiService.updateBlockFetching();\n }\n\n async getBlockTimestamp(height: number): Promise<Date> {\n const block = await getBlockByHeight(this.apiService.api, height);\n\n let timestamp = getTimestamp(block);\n if (!timestamp) {\n // Not all networks have a block timestamp, e.g. Shiden\n const blockTimestamp = await (\n await this.apiService.unsafeApi.at(block.hash)\n ).query.timestamp.now();\n\n timestamp = new Date(blockTimestamp.toNumber());\n }\n\n return timestamp;\n }\n\n getBlockSize(block: IBlock): number {\n return getBlockSize(block);\n }\n\n async getFinalizedHeader(): Promise<Header> {\n const finalizedHash =\n await this.apiService.unsafeApi.rpc.chain.getFinalizedHead();\n\n return this.getHeaderForHash(finalizedHash.toHex());\n }\n\n async getBestHeight(): Promise<number> {\n const bestHeader = await this.apiService.unsafeApi.rpc.chain.getHeader();\n return bestHeader.number.toNumber();\n }\n // eslint-disable-next-line @typescript-eslint/require-await\n async getChainInterval(): Promise<number> {\n const chainInterval = calcInterval(this.apiService.unsafeApi)\n .muln(INTERVAL_PERCENT)\n .toNumber();\n\n return Math.min(BLOCK_TIME_VARIANCE, chainInterval);\n }\n\n // TODO can this decorator be in unfinalizedBlocks Service?\n @mainThreadOnly()\n async getHeaderForHash(hash: string): Promise<Header> {\n return getHeaderForHash(this.apiService.unsafeApi, hash);\n }\n\n // TODO can this decorator be in unfinalizedBlocks Service?\n @mainThreadOnly()\n async getHeaderForHeight(height: number): Promise<Header> {\n const hash = await this.apiService.unsafeApi.rpc.chain.getBlockHash(height);\n return this.getHeaderForHash(hash.toHex());\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async updateDynamicDs(\n params: DatasourceParams,\n dsObj: SubstrateProjectDs,\n ): Promise<void> {\n if (isCustomDs(dsObj)) {\n dsObj.processor.options = {\n ...dsObj.processor.options,\n ...params.args,\n };\n // TODO needs dsProcessorService\n // await this.dsProcessorService.validateCustomDs([dsObj]);\n } else if (isRuntimeDs(dsObj)) {\n // XXX add any modifications to the ds here\n }\n }\n\n async getSafeApi(block: LightBlockContent | BlockContent): Promise<ApiAt> {\n const runtimeVersion = !isFullBlock(block)\n ? undefined\n : await this.runtimeService.getRuntimeVersion(block.block);\n\n return this.apiService.getPatchedApi(\n block.block.block.header,\n runtimeVersion,\n );\n }\n}\n"]}
@@ -18,7 +18,7 @@ export declare class WorkerService extends BaseWorkerService<BlockContent | Ligh
18
18
  protected fetchChainBlock(height: number, { specVersion }: {
19
19
  specVersion: number;
20
20
  }): Promise<IBlock<BlockContent | LightBlockContent>>;
21
- protected toBlockResponse(block: BlockContent): FetchBlockResponse;
21
+ protected toBlockResponse(block: IBlock<BlockContent>): FetchBlockResponse;
22
22
  protected getBlockSize(block: IBlock<BlockContent | LightBlockContent>): number;
23
23
  protected processFetchedBlock(block: IBlock<BlockContent | LightBlockContent>, dataSources: SubstrateDatasource[]): Promise<ProcessBlockResponse>;
24
24
  getSpecFromMap(height: number): number | undefined;
@@ -17,7 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.WorkerService = void 0;
18
18
  const common_1 = require("@nestjs/common");
19
19
  const node_core_1 = require("@subql/node-core");
20
- const substrate_1 = require("../../utils/substrate");
21
20
  const api_service_1 = require("../api.service");
22
21
  const indexer_manager_1 = require("../indexer.manager");
23
22
  const workerRuntimeService_1 = require("../runtime/workerRuntimeService");
@@ -38,10 +37,10 @@ let WorkerService = class WorkerService extends node_core_1.BaseWorkerService {
38
37
  return block;
39
38
  }
40
39
  // TODO test this with LightBlockContent
41
- toBlockResponse(block /* | LightBlockContent*/) {
40
+ toBlockResponse(block /*| IBlock<LightBlockContent>*/) {
42
41
  return {
43
- ...(0, substrate_1.substrateBlockToHeader)(block.block),
44
- specVersion: block.block.specVersion,
42
+ ...block.getHeader(),
43
+ specVersion: block.block.block.specVersion,
45
44
  };
46
45
  }
47
46
  getBlockSize(block) {
@@ -1 +1 @@
1
- {"version":3,"file":"worker.service.js","sourceRoot":"","sources":["../../../src/indexer/worker/worker.service.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;;;;;;;;;;;;;;AAEnC,2CAAoD;AACpD,gDAQ0B;AAE1B,qDAA+D;AAC/D,gDAA4C;AAE5C,wDAAoD;AACpD,0EAAuE;AACvE,oCAAyE;AAKlE,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,6BAKlC;IAEiC;IACtB;IAEA;IAJV,YACgC,UAAsB,EAC5C,cAA8B,EAE9B,oBAA0C,EAElD,cAAoD,EAEpD,qBAA6C,EAC7C,UAAsB;QAEtB,KAAK,CAAC,cAAc,EAAE,qBAAqB,EAAE,UAAU,CAAC,CAAC;QAV3B,eAAU,GAAV,UAAU,CAAY;QAC5C,mBAAc,GAAd,cAAc,CAAgB;QAE9B,yBAAoB,GAApB,oBAAoB,CAAsB;IAQpD,CAAC;IAES,KAAK,CAAC,eAAe,CAC7B,MAAc,EACd,EAAE,WAAW,EAA2B;QAExC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAC7D,MAAM,EACN,WAAW,CACZ,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAC/C,CAAC,MAAM,CAAC,EACR,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CACtE,CAAC;QAEF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wCAAwC;IAC9B,eAAe,CACvB,KAAmB,CAAC,wBAAwB;QAE5C,OAAO;YACL,GAAG,IAAA,kCAAsB,EAAC,KAAK,CAAC,KAAK,CAAC;YACtC,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW;SACrC,CAAC;IACJ,CAAC;IAES,YAAY,CACpB,KAA+C;QAE/C,OAAO,IAAA,oBAAY,EAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAES,KAAK,CAAC,mBAAmB,CACjC,KAA+C,EAC/C,WAAkC;QAElC,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC5D,CAAC;IAED,cAAc,CAAC,MAAc;QAC3B,OAAO,IAAI,CAAC,oBAAoB,CAAC,cAAc,CAC7C,MAAM,EACN,IAAI,CAAC,oBAAoB,CAAC,cAAc,CACzC,CAAC;IACJ,CAAC;IAED,kBAAkB,CAChB,YAA2B,EAC3B,qBAA8B;QAE9B,IAAI,CAAC,oBAAoB,CAAC,kBAAkB,CAC1C,YAAY,EACZ,qBAAqB,CACtB,CAAC;IACJ,CAAC;CACF,CAAA;AA5EY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;IAQR,WAAA,IAAA,eAAM,EAAC,YAAY,CAAC,CAAA;IAEpB,WAAA,IAAA,eAAM,EAAC,gBAAgB,CAAC,CAAA;IAExB,WAAA,IAAA,eAAM,EAAC,iBAAiB,CAAC,CAAA;IAEzB,WAAA,IAAA,eAAM,EAAC,wBAAwB,CAAC,CAAA;qCANS,wBAAU;QAC5B,gCAAc;QAER,2CAAoB,kBAKtC,sBAAU;GAfb,aAAa,CA4EzB","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 NodeConfig,\n IProjectService,\n ProcessBlockResponse,\n BaseWorkerService,\n IProjectUpgradeService,\n IBlock,\n Header,\n} from '@subql/node-core';\nimport { SubstrateDatasource } from '@subql/types';\nimport { substrateBlockToHeader } from '../../utils/substrate';\nimport { ApiService } from '../api.service';\nimport { SpecVersion } from '../dictionary';\nimport { IndexerManager } from '../indexer.manager';\nimport { WorkerRuntimeService } from '../runtime/workerRuntimeService';\nimport { BlockContent, getBlockSize, LightBlockContent } from '../types';\n\nexport type FetchBlockResponse = Header & { specVersion?: number };\n\n@Injectable()\nexport class WorkerService extends BaseWorkerService<\n BlockContent | LightBlockContent,\n FetchBlockResponse,\n SubstrateDatasource,\n { specVersion: number }\n> {\n constructor(\n @Inject('APIService') private apiService: ApiService,\n private indexerManager: IndexerManager,\n @Inject('RuntimeService')\n private workerRuntimeService: WorkerRuntimeService,\n @Inject('IProjectService')\n projectService: IProjectService<SubstrateDatasource>,\n @Inject('IProjectUpgradeService')\n projectUpgradeService: IProjectUpgradeService,\n nodeConfig: NodeConfig,\n ) {\n super(projectService, projectUpgradeService, nodeConfig);\n }\n\n protected async fetchChainBlock(\n height: number,\n { specVersion }: { specVersion: number },\n ): Promise<IBlock<BlockContent | LightBlockContent>> {\n const specChanged = await this.workerRuntimeService.specChanged(\n height,\n specVersion,\n );\n\n const [block] = await this.apiService.fetchBlocks(\n [height],\n specChanged ? undefined : this.workerRuntimeService.parentSpecVersion,\n );\n\n return block;\n }\n\n // TODO test this with LightBlockContent\n protected toBlockResponse(\n block: BlockContent /* | LightBlockContent*/,\n ): FetchBlockResponse {\n return {\n ...substrateBlockToHeader(block.block),\n specVersion: block.block.specVersion,\n };\n }\n\n protected getBlockSize(\n block: IBlock<BlockContent | LightBlockContent>,\n ): number {\n return getBlockSize(block);\n }\n\n protected async processFetchedBlock(\n block: IBlock<BlockContent | LightBlockContent>,\n dataSources: SubstrateDatasource[],\n ): Promise<ProcessBlockResponse> {\n return this.indexerManager.indexBlock(block, dataSources);\n }\n\n getSpecFromMap(height: number): number | undefined {\n return this.workerRuntimeService.getSpecFromMap(\n height,\n this.workerRuntimeService.specVersionMap,\n );\n }\n\n syncRuntimeService(\n specVersions: SpecVersion[],\n latestFinalizedHeight?: number,\n ): void {\n this.workerRuntimeService.syncSpecVersionMap(\n specVersions,\n latestFinalizedHeight,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"worker.service.js","sourceRoot":"","sources":["../../../src/indexer/worker/worker.service.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;;;;;;;;;;;;;;AAEnC,2CAAoD;AACpD,gDAQ0B;AAG1B,gDAA4C;AAE5C,wDAAoD;AACpD,0EAAuE;AACvE,oCAAyE;AAKlE,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,6BAKlC;IAEiC;IACtB;IAEA;IAJV,YACgC,UAAsB,EAC5C,cAA8B,EAE9B,oBAA0C,EAElD,cAAoD,EAEpD,qBAA6C,EAC7C,UAAsB;QAEtB,KAAK,CAAC,cAAc,EAAE,qBAAqB,EAAE,UAAU,CAAC,CAAC;QAV3B,eAAU,GAAV,UAAU,CAAY;QAC5C,mBAAc,GAAd,cAAc,CAAgB;QAE9B,yBAAoB,GAApB,oBAAoB,CAAsB;IAQpD,CAAC;IAES,KAAK,CAAC,eAAe,CAC7B,MAAc,EACd,EAAE,WAAW,EAA2B;QAExC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAC7D,MAAM,EACN,WAAW,CACZ,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAC/C,CAAC,MAAM,CAAC,EACR,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CACtE,CAAC;QAEF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wCAAwC;IAC9B,eAAe,CACvB,KAA2B,CAAC,+BAA+B;QAE3D,OAAO;YACL,GAAG,KAAK,CAAC,SAAS,EAAE;YACpB,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW;SAC3C,CAAC;IACJ,CAAC;IAES,YAAY,CACpB,KAA+C;QAE/C,OAAO,IAAA,oBAAY,EAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAES,KAAK,CAAC,mBAAmB,CACjC,KAA+C,EAC/C,WAAkC;QAElC,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC5D,CAAC;IAED,cAAc,CAAC,MAAc;QAC3B,OAAO,IAAI,CAAC,oBAAoB,CAAC,cAAc,CAC7C,MAAM,EACN,IAAI,CAAC,oBAAoB,CAAC,cAAc,CACzC,CAAC;IACJ,CAAC;IAED,kBAAkB,CAChB,YAA2B,EAC3B,qBAA8B;QAE9B,IAAI,CAAC,oBAAoB,CAAC,kBAAkB,CAC1C,YAAY,EACZ,qBAAqB,CACtB,CAAC;IACJ,CAAC;CACF,CAAA;AA5EY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;IAQR,WAAA,IAAA,eAAM,EAAC,YAAY,CAAC,CAAA;IAEpB,WAAA,IAAA,eAAM,EAAC,gBAAgB,CAAC,CAAA;IAExB,WAAA,IAAA,eAAM,EAAC,iBAAiB,CAAC,CAAA;IAEzB,WAAA,IAAA,eAAM,EAAC,wBAAwB,CAAC,CAAA;qCANS,wBAAU;QAC5B,gCAAc;QAER,2CAAoB,kBAKtC,sBAAU;GAfb,aAAa,CA4EzB","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 NodeConfig,\n IProjectService,\n ProcessBlockResponse,\n BaseWorkerService,\n IProjectUpgradeService,\n IBlock,\n Header,\n} from '@subql/node-core';\nimport { SubstrateDatasource } from '@subql/types';\nimport { substrateBlockToHeader } from '../../utils/substrate';\nimport { ApiService } from '../api.service';\nimport { SpecVersion } from '../dictionary';\nimport { IndexerManager } from '../indexer.manager';\nimport { WorkerRuntimeService } from '../runtime/workerRuntimeService';\nimport { BlockContent, getBlockSize, LightBlockContent } from '../types';\n\nexport type FetchBlockResponse = Header & { specVersion?: number };\n\n@Injectable()\nexport class WorkerService extends BaseWorkerService<\n BlockContent | LightBlockContent,\n FetchBlockResponse,\n SubstrateDatasource,\n { specVersion: number }\n> {\n constructor(\n @Inject('APIService') private apiService: ApiService,\n private indexerManager: IndexerManager,\n @Inject('RuntimeService')\n private workerRuntimeService: WorkerRuntimeService,\n @Inject('IProjectService')\n projectService: IProjectService<SubstrateDatasource>,\n @Inject('IProjectUpgradeService')\n projectUpgradeService: IProjectUpgradeService,\n nodeConfig: NodeConfig,\n ) {\n super(projectService, projectUpgradeService, nodeConfig);\n }\n\n protected async fetchChainBlock(\n height: number,\n { specVersion }: { specVersion: number },\n ): Promise<IBlock<BlockContent | LightBlockContent>> {\n const specChanged = await this.workerRuntimeService.specChanged(\n height,\n specVersion,\n );\n\n const [block] = await this.apiService.fetchBlocks(\n [height],\n specChanged ? undefined : this.workerRuntimeService.parentSpecVersion,\n );\n\n return block;\n }\n\n // TODO test this with LightBlockContent\n protected toBlockResponse(\n block: IBlock<BlockContent> /*| IBlock<LightBlockContent>*/,\n ): FetchBlockResponse {\n return {\n ...block.getHeader(),\n specVersion: block.block.block.specVersion,\n };\n }\n\n protected getBlockSize(\n block: IBlock<BlockContent | LightBlockContent>,\n ): number {\n return getBlockSize(block);\n }\n\n protected async processFetchedBlock(\n block: IBlock<BlockContent | LightBlockContent>,\n dataSources: SubstrateDatasource[],\n ): Promise<ProcessBlockResponse> {\n return this.indexerManager.indexBlock(block, dataSources);\n }\n\n getSpecFromMap(height: number): number | undefined {\n return this.workerRuntimeService.getSpecFromMap(\n height,\n this.workerRuntimeService.specVersionMap,\n );\n }\n\n syncRuntimeService(\n specVersions: SpecVersion[],\n latestFinalizedHeight?: number,\n ): void {\n this.workerRuntimeService.syncSpecVersionMap(\n specVersions,\n latestFinalizedHeight,\n );\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subql/node",
3
- "version": "6.4.5-0",
3
+ "version": "6.4.6-0",
4
4
  "description": "",
5
5
  "author": "Ian He",
6
6
  "license": "GPL-3.0",
@@ -27,7 +27,7 @@
27
27
  "@nestjs/schedule": "^5.0.1",
28
28
  "@polkadot/api": "^16.4.7",
29
29
  "@subql/common-substrate": "~4.5.5",
30
- "@subql/node-core": "~18.5.3-0",
30
+ "@subql/node-core": "~18.5.4-0",
31
31
  "@subql/types": "~3.15.0",
32
32
  "@subql/utils": "~2.22.1",
33
33
  "fetch-h2": "3.0.2",
@@ -59,5 +59,5 @@
59
59
  "README.md",
60
60
  "CHANGELOG.md"
61
61
  ],
62
- "stableVersion": "6.4.4"
62
+ "stableVersion": "6.4.5"
63
63
  }