@subql/node-ethereum 0.1.1 → 0.2.1

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/indexer/blockDispatcher/base-block-dispatcher.d.ts +40 -0
  4. package/dist/indexer/blockDispatcher/base-block-dispatcher.js +97 -0
  5. package/dist/indexer/blockDispatcher/base-block-dispatcher.js.map +1 -0
  6. package/dist/indexer/blockDispatcher/block-dispatcher.service.d.ts +23 -0
  7. package/dist/indexer/blockDispatcher/block-dispatcher.service.js +134 -0
  8. package/dist/indexer/blockDispatcher/block-dispatcher.service.js.map +1 -0
  9. package/dist/indexer/blockDispatcher/index.d.ts +4 -0
  10. package/dist/indexer/blockDispatcher/index.js +10 -0
  11. package/dist/indexer/blockDispatcher/index.js.map +1 -0
  12. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.d.ts +20 -0
  13. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js +170 -0
  14. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js.map +1 -0
  15. package/dist/indexer/dynamic-ds.service.d.ts +1 -0
  16. package/dist/indexer/dynamic-ds.service.js +19 -12
  17. package/dist/indexer/dynamic-ds.service.js.map +1 -1
  18. package/dist/indexer/fetch.module.js +3 -3
  19. package/dist/indexer/fetch.module.js.map +1 -1
  20. package/dist/indexer/fetch.service.d.ts +6 -4
  21. package/dist/indexer/fetch.service.js +45 -16
  22. package/dist/indexer/fetch.service.js.map +1 -1
  23. package/dist/indexer/indexer.manager.d.ts +1 -0
  24. package/dist/indexer/indexer.manager.js +2 -1
  25. package/dist/indexer/indexer.manager.js.map +1 -1
  26. package/dist/indexer/project.service.d.ts +3 -0
  27. package/dist/indexer/project.service.js +18 -0
  28. package/dist/indexer/project.service.js.map +1 -1
  29. package/dist/indexer/worker/worker.service.d.ts +1 -0
  30. package/dist/indexer/worker/worker.service.js.map +1 -1
  31. package/dist/main.js +3 -0
  32. package/dist/main.js.map +1 -1
  33. package/dist/subcommands/reindex.init.js +1 -0
  34. package/dist/subcommands/reindex.init.js.map +1 -1
  35. package/dist/subcommands/reindex.module.js +10 -1
  36. package/dist/subcommands/reindex.module.js.map +1 -1
  37. package/dist/subcommands/reindex.service.d.ts +4 -3
  38. package/dist/subcommands/reindex.service.js +21 -42
  39. package/dist/subcommands/reindex.service.js.map +1 -1
  40. package/dist/utils/project.js +21 -0
  41. package/dist/utils/project.js.map +1 -1
  42. package/dist/utils/reindex.d.ts +5 -0
  43. package/dist/utils/reindex.js +48 -0
  44. package/dist/utils/reindex.js.map +1 -0
  45. package/dist/yargs.d.ts +7 -1
  46. package/dist/yargs.js +6 -0
  47. package/dist/yargs.js.map +1 -1
  48. package/package.json +5 -5
  49. package/dist/indexer/worker/block-dispatcher.service.d.ts +0 -69
  50. package/dist/indexer/worker/block-dispatcher.service.js +0 -356
  51. package/dist/indexer/worker/block-dispatcher.service.js.map +0 -1
@@ -0,0 +1,40 @@
1
+ import { EventEmitter2 } from '@nestjs/event-emitter';
2
+ import { IQueue, NodeConfig } from '@subql/node-core';
3
+ import { ProjectService } from '../project.service';
4
+ export declare type ProcessBlockResponse = {
5
+ dynamicDsCreated: boolean;
6
+ operationHash: Uint8Array;
7
+ reindexBlockHeight: number;
8
+ };
9
+ export interface IBlockDispatcher {
10
+ init(onDynamicDsCreated: (height: number) => Promise<void>): Promise<void>;
11
+ enqueueBlocks(heights: number[]): void;
12
+ queueSize: number;
13
+ freeSize: number;
14
+ latestBufferedHeight: number | undefined;
15
+ flushQueue(height: number): void;
16
+ rewind(height: number): Promise<void>;
17
+ }
18
+ export declare abstract class BaseBlockDispatcher<Q extends IQueue> implements IBlockDispatcher {
19
+ protected nodeConfig: NodeConfig;
20
+ protected eventEmitter: EventEmitter2;
21
+ protected projectService: ProjectService;
22
+ protected queue: Q;
23
+ protected _latestBufferedHeight: number;
24
+ protected _processedBlockCount: number;
25
+ protected latestProcessedHeight: number;
26
+ protected currentProcessingHeight: number;
27
+ protected onDynamicDsCreated: (height: number) => Promise<void>;
28
+ constructor(nodeConfig: NodeConfig, eventEmitter: EventEmitter2, projectService: ProjectService, queue: Q);
29
+ abstract enqueueBlocks(heights: number[]): void;
30
+ abstract init(onDynamicDsCreated: (height: number) => Promise<void>): Promise<void>;
31
+ get queueSize(): number;
32
+ get freeSize(): number;
33
+ get latestBufferedHeight(): number;
34
+ set latestBufferedHeight(height: number);
35
+ protected setProcessedBlockCount(processedBlockCount: number): void;
36
+ rewind(lastCorrectHeight: number): Promise<void>;
37
+ flushQueue(height: number): void;
38
+ protected preProcessBlock(height: number): void;
39
+ protected postProcessBlock(height: number, processBlockResponse: ProcessBlockResponse): Promise<void>;
40
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ // Copyright 2020-2021 OnFinality Limited authors & contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.BaseBlockDispatcher = void 0;
9
+ const assert_1 = __importDefault(require("assert"));
10
+ const util_1 = require("@polkadot/util");
11
+ const node_core_1 = require("@subql/node-core");
12
+ const logger = (0, node_core_1.getLogger)('BaseBlockDispatcherService');
13
+ const NULL_MERKEL_ROOT = (0, util_1.hexToU8a)('0x00');
14
+ function isNullMerkelRoot(operationHash) {
15
+ return (0, util_1.u8aEq)(operationHash, NULL_MERKEL_ROOT);
16
+ }
17
+ class BaseBlockDispatcher {
18
+ constructor(nodeConfig, eventEmitter, projectService, queue) {
19
+ this.nodeConfig = nodeConfig;
20
+ this.eventEmitter = eventEmitter;
21
+ this.projectService = projectService;
22
+ this.queue = queue;
23
+ }
24
+ get queueSize() {
25
+ return this.queue.size;
26
+ }
27
+ get freeSize() {
28
+ return this.queue.freeSpace;
29
+ }
30
+ get latestBufferedHeight() {
31
+ return this._latestBufferedHeight;
32
+ }
33
+ set latestBufferedHeight(height) {
34
+ this.eventEmitter.emit(node_core_1.IndexerEvent.BlocknumberQueueSize, {
35
+ value: this.queueSize,
36
+ });
37
+ this._latestBufferedHeight = height;
38
+ }
39
+ setProcessedBlockCount(processedBlockCount) {
40
+ this._processedBlockCount = processedBlockCount;
41
+ this.eventEmitter.emit(node_core_1.IndexerEvent.BlockProcessedCount, {
42
+ processedBlockCount,
43
+ timestamp: Date.now(),
44
+ });
45
+ }
46
+ // Compare it with current indexing number, if last corrected is already indexed
47
+ // rewind, also flush queued blocks, drop current indexing transaction, set last processed to correct block too
48
+ // if rollback is greater than current index flush queue only
49
+ async rewind(lastCorrectHeight) {
50
+ if (lastCorrectHeight <= this.currentProcessingHeight) {
51
+ logger.info(`Found last verified block at height ${lastCorrectHeight}, rewinding...`);
52
+ await this.projectService.reindex(lastCorrectHeight);
53
+ this.latestProcessedHeight = lastCorrectHeight;
54
+ logger.info(`Successful rewind to block ${lastCorrectHeight}!`);
55
+ }
56
+ this.flushQueue(lastCorrectHeight);
57
+ logger.info(`Queued blocks flushed!`); //Also last buffered height reset, next fetching should start after lastCorrectHeight
58
+ }
59
+ flushQueue(height) {
60
+ this.latestBufferedHeight = height;
61
+ this.queue.flush();
62
+ }
63
+ // Is called directly before a block is processed
64
+ preProcessBlock(height) {
65
+ this.currentProcessingHeight = height;
66
+ this.eventEmitter.emit(node_core_1.IndexerEvent.BlockProcessing, {
67
+ height,
68
+ timestamp: Date.now(),
69
+ });
70
+ }
71
+ // Is called directly after a block is processed
72
+ async postProcessBlock(height, processBlockResponse) {
73
+ const { dynamicDsCreated, operationHash, reindexBlockHeight } = processBlockResponse;
74
+ if (reindexBlockHeight !== null && reindexBlockHeight !== undefined) {
75
+ await this.rewind(reindexBlockHeight);
76
+ this.latestProcessedHeight = reindexBlockHeight;
77
+ }
78
+ else {
79
+ if (this.nodeConfig.proofOfIndex && !isNullMerkelRoot(operationHash)) {
80
+ if (!this.projectService.blockOffset) {
81
+ // Which means during project init, it has not found offset and set value
82
+ await this.projectService.upsertMetadataBlockOffset(height - 1);
83
+ }
84
+ void this.projectService.setBlockOffset(height - 1);
85
+ }
86
+ if (dynamicDsCreated) {
87
+ await this.onDynamicDsCreated(height);
88
+ }
89
+ (0, assert_1.default)(!this.latestProcessedHeight || height > this.latestProcessedHeight, `Block processed out of order. Height: ${height}. Latest: ${this.latestProcessedHeight}`);
90
+ // In memory _processedBlockCount increase, db metadata increase BlockCount in indexer.manager
91
+ this.setProcessedBlockCount(this._processedBlockCount + 1);
92
+ this.latestProcessedHeight = height;
93
+ }
94
+ }
95
+ }
96
+ exports.BaseBlockDispatcher = BaseBlockDispatcher;
97
+ //# sourceMappingURL=base-block-dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-block-dispatcher.js","sourceRoot":"","sources":["../../../src/indexer/blockDispatcher/base-block-dispatcher.ts"],"names":[],"mappings":";AAAA,gEAAgE;AAChE,sCAAsC;;;;;;AAEtC,oDAA4B;AAE5B,yCAAiD;AACjD,gDAA+E;AAG/E,MAAM,MAAM,GAAG,IAAA,qBAAS,EAAC,4BAA4B,CAAC,CAAC;AAsBvD,MAAM,gBAAgB,GAAG,IAAA,eAAQ,EAAC,MAAM,CAAC,CAAC;AAE1C,SAAS,gBAAgB,CAAC,aAAyB;IACjD,OAAO,IAAA,YAAK,EAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAChD,CAAC;AAED,MAAsB,mBAAmB;IASvC,YACY,UAAsB,EACtB,YAA2B,EAC3B,cAA8B,EAC9B,KAAQ;QAHR,eAAU,GAAV,UAAU,CAAY;QACtB,iBAAY,GAAZ,YAAY,CAAe;QAC3B,mBAAc,GAAd,cAAc,CAAgB;QAC9B,UAAK,GAAL,KAAK,CAAG;IACjB,CAAC;IAOJ,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;IAC9B,CAAC;IAED,IAAI,oBAAoB;QACtB,OAAO,IAAI,CAAC,qBAAqB,CAAC;IACpC,CAAC;IAED,IAAI,oBAAoB,CAAC,MAAc;QACrC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,wBAAY,CAAC,oBAAoB,EAAE;YACxD,KAAK,EAAE,IAAI,CAAC,SAAS;SACtB,CAAC,CAAC;QACH,IAAI,CAAC,qBAAqB,GAAG,MAAM,CAAC;IACtC,CAAC;IAES,sBAAsB,CAAC,mBAA2B;QAC1D,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;QAChD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,wBAAY,CAAC,mBAAmB,EAAE;YACvD,mBAAmB;YACnB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;IACL,CAAC;IAED,iFAAiF;IACjF,gHAAgH;IAChH,8DAA8D;IAC9D,KAAK,CAAC,MAAM,CAAC,iBAAyB;QACpC,IAAI,iBAAiB,IAAI,IAAI,CAAC,uBAAuB,EAAE;YACrD,MAAM,CAAC,IAAI,CACT,uCAAuC,iBAAiB,gBAAgB,CACzE,CAAC;YACF,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;YACrD,IAAI,CAAC,qBAAqB,GAAG,iBAAiB,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,8BAA8B,iBAAiB,GAAG,CAAC,CAAC;SACjE;QACD,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,qFAAqF;IAC9H,CAAC;IAED,UAAU,CAAC,MAAc;QACvB,IAAI,CAAC,oBAAoB,GAAG,MAAM,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,iDAAiD;IACvC,eAAe,CAAC,MAAc;QACtC,IAAI,CAAC,uBAAuB,GAAG,MAAM,CAAC;QACtC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,wBAAY,CAAC,eAAe,EAAE;YACnD,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;IACL,CAAC;IAED,gDAAgD;IACtC,KAAK,CAAC,gBAAgB,CAC9B,MAAc,EACd,oBAA0C;QAE1C,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,kBAAkB,EAAE,GAC3D,oBAAoB,CAAC;QACvB,IAAI,kBAAkB,KAAK,IAAI,IAAI,kBAAkB,KAAK,SAAS,EAAE;YACnE,MAAM,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;YACtC,IAAI,CAAC,qBAAqB,GAAG,kBAAkB,CAAC;SACjD;aAAM;YACL,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAAE;gBACpE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE;oBACpC,yEAAyE;oBACzE,MAAM,IAAI,CAAC,cAAc,CAAC,yBAAyB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;iBACjE;gBACD,KAAK,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;aACrD;YACD,IAAI,gBAAgB,EAAE;gBACpB,MAAM,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;aACvC;YACD,IAAA,gBAAM,EACJ,CAAC,IAAI,CAAC,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAAC,qBAAqB,EAClE,yCAAyC,MAAM,aAAa,IAAI,CAAC,qBAAqB,EAAE,CACzF,CAAC;YACF,8FAA8F;YAC9F,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC,CAAC;YAC3D,IAAI,CAAC,qBAAqB,GAAG,MAAM,CAAC;SACrC;IACH,CAAC;CACF;AA5GD,kDA4GC","sourcesContent":["// Copyright 2020-2021 OnFinality Limited authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport assert from 'assert';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { hexToU8a, u8aEq } from '@polkadot/util';\nimport { getLogger, IndexerEvent, IQueue, NodeConfig } from '@subql/node-core';\nimport { ProjectService } from '../project.service';\n\nconst logger = getLogger('BaseBlockDispatcherService');\n\nexport type ProcessBlockResponse = {\n dynamicDsCreated: boolean;\n operationHash: Uint8Array;\n reindexBlockHeight: number;\n};\n\nexport interface IBlockDispatcher {\n init(onDynamicDsCreated: (height: number) => Promise<void>): Promise<void>;\n\n enqueueBlocks(heights: number[]): void;\n\n queueSize: number;\n freeSize: number;\n latestBufferedHeight: number | undefined;\n\n // Remove all enqueued blocks, used when a dynamic ds is created\n flushQueue(height: number): void;\n rewind(height: number): Promise<void>;\n}\n\nconst NULL_MERKEL_ROOT = hexToU8a('0x00');\n\nfunction isNullMerkelRoot(operationHash: Uint8Array): boolean {\n return u8aEq(operationHash, NULL_MERKEL_ROOT);\n}\n\nexport abstract class BaseBlockDispatcher<Q extends IQueue>\n implements IBlockDispatcher\n{\n protected _latestBufferedHeight: number;\n protected _processedBlockCount: number;\n protected latestProcessedHeight: number;\n protected currentProcessingHeight: number;\n protected onDynamicDsCreated: (height: number) => Promise<void>;\n\n constructor(\n protected nodeConfig: NodeConfig,\n protected eventEmitter: EventEmitter2,\n protected projectService: ProjectService,\n protected queue: Q,\n ) {}\n\n abstract enqueueBlocks(heights: number[]): void;\n abstract init(\n onDynamicDsCreated: (height: number) => Promise<void>,\n ): Promise<void>;\n\n get queueSize(): number {\n return this.queue.size;\n }\n\n get freeSize(): number {\n return this.queue.freeSpace;\n }\n\n get latestBufferedHeight(): number {\n return this._latestBufferedHeight;\n }\n\n set latestBufferedHeight(height: number) {\n this.eventEmitter.emit(IndexerEvent.BlocknumberQueueSize, {\n value: this.queueSize,\n });\n this._latestBufferedHeight = height;\n }\n\n protected setProcessedBlockCount(processedBlockCount: number): void {\n this._processedBlockCount = processedBlockCount;\n this.eventEmitter.emit(IndexerEvent.BlockProcessedCount, {\n processedBlockCount,\n timestamp: Date.now(),\n });\n }\n\n // Compare it with current indexing number, if last corrected is already indexed\n // rewind, also flush queued blocks, drop current indexing transaction, set last processed to correct block too\n // if rollback is greater than current index flush queue only\n async rewind(lastCorrectHeight: number): Promise<void> {\n if (lastCorrectHeight <= this.currentProcessingHeight) {\n logger.info(\n `Found last verified block at height ${lastCorrectHeight}, rewinding...`,\n );\n await this.projectService.reindex(lastCorrectHeight);\n this.latestProcessedHeight = lastCorrectHeight;\n logger.info(`Successful rewind to block ${lastCorrectHeight}!`);\n }\n this.flushQueue(lastCorrectHeight);\n logger.info(`Queued blocks flushed!`); //Also last buffered height reset, next fetching should start after lastCorrectHeight\n }\n\n flushQueue(height: number): void {\n this.latestBufferedHeight = height;\n this.queue.flush();\n }\n\n // Is called directly before a block is processed\n protected preProcessBlock(height: number): void {\n this.currentProcessingHeight = height;\n this.eventEmitter.emit(IndexerEvent.BlockProcessing, {\n height,\n timestamp: Date.now(),\n });\n }\n\n // Is called directly after a block is processed\n protected async postProcessBlock(\n height: number,\n processBlockResponse: ProcessBlockResponse,\n ): Promise<void> {\n const { dynamicDsCreated, operationHash, reindexBlockHeight } =\n processBlockResponse;\n if (reindexBlockHeight !== null && reindexBlockHeight !== undefined) {\n await this.rewind(reindexBlockHeight);\n this.latestProcessedHeight = reindexBlockHeight;\n } else {\n if (this.nodeConfig.proofOfIndex && !isNullMerkelRoot(operationHash)) {\n if (!this.projectService.blockOffset) {\n // Which means during project init, it has not found offset and set value\n await this.projectService.upsertMetadataBlockOffset(height - 1);\n }\n void this.projectService.setBlockOffset(height - 1);\n }\n if (dynamicDsCreated) {\n await this.onDynamicDsCreated(height);\n }\n assert(\n !this.latestProcessedHeight || height > this.latestProcessedHeight,\n `Block processed out of order. Height: ${height}. Latest: ${this.latestProcessedHeight}`,\n );\n // In memory _processedBlockCount increase, db metadata increase BlockCount in indexer.manager\n this.setProcessedBlockCount(this._processedBlockCount + 1);\n this.latestProcessedHeight = height;\n }\n }\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import { OnApplicationShutdown } from '@nestjs/common';
2
+ import { EventEmitter2 } from '@nestjs/event-emitter';
3
+ import { ApiService, NodeConfig, Queue } from '@subql/node-core';
4
+ import { IndexerManager } from '../indexer.manager';
5
+ import { ProjectService } from '../project.service';
6
+ import { BaseBlockDispatcher } from './base-block-dispatcher';
7
+ /**
8
+ * @description Intended to behave the same as WorkerBlockDispatcherService but doesn't use worker threads or any parallel processing
9
+ */
10
+ export declare class BlockDispatcherService extends BaseBlockDispatcher<Queue<number>> implements OnApplicationShutdown {
11
+ private apiService;
12
+ private indexerManager;
13
+ private processQueue;
14
+ private fetching;
15
+ private isShutdown;
16
+ private fetchBlocksBatches;
17
+ constructor(apiService: ApiService, nodeConfig: NodeConfig, indexerManager: IndexerManager, eventEmitter: EventEmitter2, projectService: ProjectService);
18
+ init(onDynamicDsCreated: (height: number) => Promise<void>): Promise<void>;
19
+ onApplicationShutdown(): void;
20
+ enqueueBlocks(heights: number[]): void;
21
+ flushQueue(height: number): void;
22
+ private fetchBlocksFromQueue;
23
+ }
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ // Copyright 2020-2021 OnFinality Limited authors & contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
5
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
6
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
7
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
9
+ };
10
+ var __metadata = (this && this.__metadata) || function (k, v) {
11
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.BlockDispatcherService = void 0;
15
+ const common_1 = require("@nestjs/common");
16
+ const event_emitter_1 = require("@nestjs/event-emitter");
17
+ const node_core_1 = require("@subql/node-core");
18
+ const lodash_1 = require("lodash");
19
+ const indexer_manager_1 = require("../indexer.manager");
20
+ const project_service_1 = require("../project.service");
21
+ const base_block_dispatcher_1 = require("./base-block-dispatcher");
22
+ const logger = (0, node_core_1.getLogger)('BlockDispatcherService');
23
+ /**
24
+ * @description Intended to behave the same as WorkerBlockDispatcherService but doesn't use worker threads or any parallel processing
25
+ */
26
+ let BlockDispatcherService = class BlockDispatcherService extends base_block_dispatcher_1.BaseBlockDispatcher {
27
+ constructor(apiService, nodeConfig, indexerManager, eventEmitter, projectService) {
28
+ super(nodeConfig, eventEmitter, projectService, new node_core_1.Queue(nodeConfig.batchSize * 3));
29
+ this.apiService = apiService;
30
+ this.indexerManager = indexerManager;
31
+ this.fetching = false;
32
+ this.isShutdown = false;
33
+ this.processQueue = new node_core_1.AutoQueue(nodeConfig.batchSize * 3);
34
+ const fetchBlocks = this.apiService.api.fetchBlocks.bind(this.apiService.api);
35
+ if (this.nodeConfig.profiler) {
36
+ this.fetchBlocksBatches = (0, node_core_1.profilerWrap)(fetchBlocks, 'EthereumUtil', 'fetchBlocksBatches');
37
+ }
38
+ else {
39
+ this.fetchBlocksBatches = fetchBlocks;
40
+ }
41
+ }
42
+ // eslint-disable-next-line @typescript-eslint/require-await
43
+ async init(onDynamicDsCreated) {
44
+ this.onDynamicDsCreated = onDynamicDsCreated;
45
+ const blockAmount = await this.projectService.getProcessedBlockCount();
46
+ this.setProcessedBlockCount(blockAmount !== null && blockAmount !== void 0 ? blockAmount : 0);
47
+ }
48
+ onApplicationShutdown() {
49
+ this.isShutdown = true;
50
+ this.processQueue.abort();
51
+ }
52
+ enqueueBlocks(heights) {
53
+ if (!heights.length)
54
+ return;
55
+ logger.info(`Enqueing blocks ${heights[0]}...${(0, lodash_1.last)(heights)}, total ${heights.length} blocks`);
56
+ this.queue.putMany(heights);
57
+ this.latestBufferedHeight = (0, lodash_1.last)(heights);
58
+ void this.fetchBlocksFromQueue().catch((e) => {
59
+ logger.error(e, 'Failed to fetch blocks from queue');
60
+ if (!this.isShutdown) {
61
+ process.exit(1);
62
+ }
63
+ });
64
+ }
65
+ flushQueue(height) {
66
+ super.flushQueue(height);
67
+ this.processQueue.flush();
68
+ }
69
+ async fetchBlocksFromQueue() {
70
+ if (this.fetching || this.isShutdown)
71
+ return;
72
+ // Process queue is full, no point in fetching more blocks
73
+ // if (this.processQueue.freeSpace < this.nodeConfig.batchSize) return;
74
+ this.fetching = true;
75
+ try {
76
+ while (!this.isShutdown) {
77
+ const blockNums = this.queue.takeMany(Math.min(this.nodeConfig.batchSize, this.processQueue.freeSpace));
78
+ // Used to compare before and after as a way to check if queue was flushed
79
+ const bufferedHeight = this._latestBufferedHeight;
80
+ // Queue is empty
81
+ if (!blockNums.length) {
82
+ // The process queue might be full so no block nums were taken, wait and try again
83
+ if (this.queue.size) {
84
+ await (0, node_core_1.delay)(1);
85
+ continue;
86
+ }
87
+ break;
88
+ }
89
+ logger.info(`fetch block [${blockNums[0]},${blockNums[blockNums.length - 1]}], total ${blockNums.length} blocks`);
90
+ const blocks = await this.fetchBlocksBatches(blockNums);
91
+ if (bufferedHeight > this._latestBufferedHeight) {
92
+ logger.debug(`Queue was reset for new DS, discarding fetched blocks`);
93
+ continue;
94
+ }
95
+ const blockTasks = blocks.map((block) => async () => {
96
+ var _a;
97
+ const height = block.block.block.header.number.toNumber();
98
+ try {
99
+ this.preProcessBlock(height);
100
+ const processBlockResponse = await this.indexerManager.indexBlock(block);
101
+ await this.postProcessBlock(height, processBlockResponse);
102
+ }
103
+ catch (e) {
104
+ if (this.isShutdown) {
105
+ return;
106
+ }
107
+ logger.error(e, `failed to index block at height ${height} ${e.handler ? `${e.handler}(${(_a = e.stack) !== null && _a !== void 0 ? _a : ''})` : ''}`);
108
+ throw e;
109
+ }
110
+ });
111
+ // There can be enough of a delay after fetching blocks that shutdown could now be true
112
+ if (this.isShutdown)
113
+ break;
114
+ this.processQueue.putMany(blockTasks);
115
+ this.eventEmitter.emit(node_core_1.IndexerEvent.BlockQueueSize, {
116
+ value: this.processQueue.size,
117
+ });
118
+ }
119
+ }
120
+ finally {
121
+ this.fetching = false;
122
+ }
123
+ }
124
+ };
125
+ BlockDispatcherService = __decorate([
126
+ (0, common_1.Injectable)(),
127
+ __metadata("design:paramtypes", [node_core_1.ApiService,
128
+ node_core_1.NodeConfig,
129
+ indexer_manager_1.IndexerManager,
130
+ event_emitter_1.EventEmitter2,
131
+ project_service_1.ProjectService])
132
+ ], BlockDispatcherService);
133
+ exports.BlockDispatcherService = BlockDispatcherService;
134
+ //# sourceMappingURL=block-dispatcher.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-dispatcher.service.js","sourceRoot":"","sources":["../../../src/indexer/blockDispatcher/block-dispatcher.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2021 OnFinality Limited authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Injectable, OnApplicationShutdown } from '@nestjs/common';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport {\n ApiService,\n getLogger,\n NodeConfig,\n IndexerEvent,\n delay,\n profilerWrap,\n AutoQueue,\n Queue,\n} from '@subql/node-core';\nimport { last } from 'lodash';\nimport { IndexerManager } from '../indexer.manager';\nimport { ProjectService } from '../project.service';\nimport { BaseBlockDispatcher } from './base-block-dispatcher';\n\nconst logger = getLogger('BlockDispatcherService');\n\n/**\n * @description Intended to behave the same as WorkerBlockDispatcherService but doesn't use worker threads or any parallel processing\n */\n@Injectable()\nexport class BlockDispatcherService\n extends BaseBlockDispatcher<Queue<number>>\n implements OnApplicationShutdown\n{\n private processQueue: AutoQueue<void>;\n\n private fetching = false;\n private isShutdown = false;\n private fetchBlocksBatches: ApiService['api']['fetchBlocks'];\n\n constructor(\n private apiService: ApiService,\n nodeConfig: NodeConfig,\n private indexerManager: IndexerManager,\n eventEmitter: EventEmitter2,\n projectService: ProjectService,\n ) {\n super(\n nodeConfig,\n eventEmitter,\n projectService,\n new Queue(nodeConfig.batchSize * 3),\n );\n this.processQueue = new AutoQueue(nodeConfig.batchSize * 3);\n\n const fetchBlocks = this.apiService.api.fetchBlocks.bind(\n this.apiService.api,\n );\n if (this.nodeConfig.profiler) {\n this.fetchBlocksBatches = profilerWrap(\n fetchBlocks,\n 'EthereumUtil',\n 'fetchBlocksBatches',\n );\n } else {\n this.fetchBlocksBatches = fetchBlocks;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async init(\n onDynamicDsCreated: (height: number) => Promise<void>,\n ): Promise<void> {\n this.onDynamicDsCreated = onDynamicDsCreated;\n const blockAmount = await this.projectService.getProcessedBlockCount();\n this.setProcessedBlockCount(blockAmount ?? 0);\n }\n\n onApplicationShutdown(): void {\n this.isShutdown = true;\n this.processQueue.abort();\n }\n\n enqueueBlocks(heights: number[]): void {\n if (!heights.length) return;\n\n logger.info(\n `Enqueing blocks ${heights[0]}...${last(heights)}, total ${\n heights.length\n } blocks`,\n );\n\n this.queue.putMany(heights);\n this.latestBufferedHeight = last(heights);\n\n void this.fetchBlocksFromQueue().catch((e) => {\n logger.error(e, 'Failed to fetch blocks from queue');\n if (!this.isShutdown) {\n process.exit(1);\n }\n });\n }\n\n flushQueue(height: number): void {\n super.flushQueue(height);\n this.processQueue.flush();\n }\n\n private async fetchBlocksFromQueue(): Promise<void> {\n if (this.fetching || this.isShutdown) return;\n // Process queue is full, no point in fetching more blocks\n // if (this.processQueue.freeSpace < this.nodeConfig.batchSize) return;\n\n this.fetching = true;\n\n try {\n while (!this.isShutdown) {\n const blockNums = this.queue.takeMany(\n Math.min(this.nodeConfig.batchSize, this.processQueue.freeSpace),\n );\n // Used to compare before and after as a way to check if queue was flushed\n const bufferedHeight = this._latestBufferedHeight;\n\n // Queue is empty\n if (!blockNums.length) {\n // The process queue might be full so no block nums were taken, wait and try again\n if (this.queue.size) {\n await delay(1);\n continue;\n }\n break;\n }\n\n logger.info(\n `fetch block [${blockNums[0]},${\n blockNums[blockNums.length - 1]\n }], total ${blockNums.length} blocks`,\n );\n\n const blocks = await this.fetchBlocksBatches(blockNums);\n\n if (bufferedHeight > this._latestBufferedHeight) {\n logger.debug(`Queue was reset for new DS, discarding fetched blocks`);\n continue;\n }\n const blockTasks = blocks.map((block) => async () => {\n const height = block.block.block.header.number.toNumber();\n try {\n this.preProcessBlock(height);\n\n const processBlockResponse = await this.indexerManager.indexBlock(\n block,\n );\n\n await this.postProcessBlock(height, processBlockResponse);\n } catch (e) {\n if (this.isShutdown) {\n return;\n }\n logger.error(\n e,\n `failed to index block at height ${height} ${\n e.handler ? `${e.handler}(${e.stack ?? ''})` : ''\n }`,\n );\n throw e;\n }\n });\n\n // There can be enough of a delay after fetching blocks that shutdown could now be true\n if (this.isShutdown) break;\n\n this.processQueue.putMany(blockTasks);\n\n this.eventEmitter.emit(IndexerEvent.BlockQueueSize, {\n value: this.processQueue.size,\n });\n }\n } finally {\n this.fetching = false;\n }\n }\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { IBlockDispatcher } from './base-block-dispatcher';
2
+ import { BlockDispatcherService } from './block-dispatcher.service';
3
+ import { WorkerBlockDispatcherService } from './worker-block-dispatcher.service';
4
+ export { IBlockDispatcher, BlockDispatcherService, WorkerBlockDispatcherService, };
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ // Copyright 2020-2021 OnFinality Limited authors & contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.WorkerBlockDispatcherService = exports.BlockDispatcherService = void 0;
6
+ const block_dispatcher_service_1 = require("./block-dispatcher.service");
7
+ Object.defineProperty(exports, "BlockDispatcherService", { enumerable: true, get: function () { return block_dispatcher_service_1.BlockDispatcherService; } });
8
+ const worker_block_dispatcher_service_1 = require("./worker-block-dispatcher.service");
9
+ Object.defineProperty(exports, "WorkerBlockDispatcherService", { enumerable: true, get: function () { return worker_block_dispatcher_service_1.WorkerBlockDispatcherService; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/indexer/blockDispatcher/index.ts"],"names":[],"mappings":";AAAA,gEAAgE;AAChE,sCAAsC;;;AAGtC,yEAAoE;AAKlE,uGALO,iDAAsB,OAKP;AAJxB,uFAAiF;AAK/E,6GALO,8DAA4B,OAKP","sourcesContent":["// Copyright 2020-2021 OnFinality Limited authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport { IBlockDispatcher } from './base-block-dispatcher';\nimport { BlockDispatcherService } from './block-dispatcher.service';\nimport { WorkerBlockDispatcherService } from './worker-block-dispatcher.service';\n\nexport {\n IBlockDispatcher,\n BlockDispatcherService,\n WorkerBlockDispatcherService,\n};\n"]}
@@ -0,0 +1,20 @@
1
+ import { OnApplicationShutdown } from '@nestjs/common';
2
+ import { EventEmitter2 } from '@nestjs/event-emitter';
3
+ import { NodeConfig, AutoQueue } from '@subql/node-core';
4
+ import { ProjectService } from '../project.service';
5
+ import { BaseBlockDispatcher } from './base-block-dispatcher';
6
+ export declare class WorkerBlockDispatcherService extends BaseBlockDispatcher<AutoQueue<void>> implements OnApplicationShutdown {
7
+ private workers;
8
+ private numWorkers;
9
+ private taskCounter;
10
+ private isShutdown;
11
+ constructor(nodeConfig: NodeConfig, eventEmitter: EventEmitter2, projectService: ProjectService);
12
+ init(onDynamicDsCreated: (height: number) => Promise<void>): Promise<void>;
13
+ onApplicationShutdown(): Promise<void>;
14
+ enqueueBlocks(heights: number[]): void;
15
+ private enqueueBlock;
16
+ sampleWorkerStatus(): Promise<void>;
17
+ get latestBufferedHeight(): number;
18
+ set latestBufferedHeight(height: number);
19
+ private getNextWorkerIndex;
20
+ }
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ // Copyright 2020-2021 OnFinality Limited authors & contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
5
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
6
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
7
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
9
+ };
10
+ var __metadata = (this && this.__metadata) || function (k, v) {
11
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.WorkerBlockDispatcherService = void 0;
18
+ const assert_1 = __importDefault(require("assert"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const common_1 = require("@nestjs/common");
21
+ const event_emitter_1 = require("@nestjs/event-emitter");
22
+ const schedule_1 = require("@nestjs/schedule");
23
+ const node_core_1 = require("@subql/node-core");
24
+ const chalk_1 = __importDefault(require("chalk"));
25
+ const lodash_1 = require("lodash");
26
+ const project_service_1 = require("../project.service");
27
+ const base_block_dispatcher_1 = require("./base-block-dispatcher");
28
+ const logger = (0, node_core_1.getLogger)('WorkerBlockDispatcherService');
29
+ async function createIndexerWorker() {
30
+ const indexerWorker = node_core_1.Worker.create(path_1.default.resolve(__dirname, '../../../dist/indexer/worker/worker.js'), [
31
+ 'initWorker',
32
+ 'processBlock',
33
+ 'fetchBlock',
34
+ 'numFetchedBlocks',
35
+ 'numFetchingBlocks',
36
+ 'getStatus',
37
+ ]);
38
+ await indexerWorker.initWorker();
39
+ return indexerWorker;
40
+ }
41
+ let WorkerBlockDispatcherService = class WorkerBlockDispatcherService extends base_block_dispatcher_1.BaseBlockDispatcher {
42
+ constructor(nodeConfig, eventEmitter, projectService) {
43
+ const numWorkers = nodeConfig.workers;
44
+ super(nodeConfig, eventEmitter, projectService, new node_core_1.AutoQueue(numWorkers * nodeConfig.batchSize * 2));
45
+ this.taskCounter = 0;
46
+ this.isShutdown = false;
47
+ this.numWorkers = numWorkers;
48
+ }
49
+ async init(onDynamicDsCreated) {
50
+ if (this.nodeConfig.unfinalizedBlocks) {
51
+ throw new Error('Sorry, best block feature is not supported with workers yet.');
52
+ }
53
+ this.workers = await Promise.all(new Array(this.numWorkers).fill(0).map(() => createIndexerWorker()));
54
+ this.onDynamicDsCreated = onDynamicDsCreated;
55
+ const blockAmount = await this.projectService.getProcessedBlockCount();
56
+ this.setProcessedBlockCount(blockAmount !== null && blockAmount !== void 0 ? blockAmount : 0);
57
+ }
58
+ async onApplicationShutdown() {
59
+ this.isShutdown = true;
60
+ // Stop processing blocks
61
+ this.queue.abort();
62
+ // Stop all workers
63
+ if (this.workers) {
64
+ await Promise.all(this.workers.map((w) => w.terminate()));
65
+ }
66
+ }
67
+ enqueueBlocks(heights) {
68
+ if (!heights.length)
69
+ return;
70
+ logger.info(`Enqueing blocks [${heights[0]}...${(0, lodash_1.last)(heights)}], total ${heights.length} blocks`);
71
+ // eslint-disable-next-line no-constant-condition
72
+ if (true) {
73
+ /*
74
+ * Load balancing:
75
+ * worker1: 1,2,3
76
+ * worker2: 4,5,6
77
+ */
78
+ const workerIdx = this.getNextWorkerIndex();
79
+ heights.map((height) => this.enqueueBlock(height, workerIdx));
80
+ }
81
+ else {
82
+ /*
83
+ * Load balancing:
84
+ * worker1: 1,3,5
85
+ * worker2: 2,4,6
86
+ */
87
+ heights.map((height) => this.enqueueBlock(height, this.getNextWorkerIndex()));
88
+ }
89
+ this.latestBufferedHeight = (0, lodash_1.last)(heights);
90
+ }
91
+ enqueueBlock(height, workerIdx) {
92
+ if (this.isShutdown)
93
+ return;
94
+ const worker = this.workers[workerIdx];
95
+ (0, assert_1.default)(worker, `Worker ${workerIdx} not found`);
96
+ // Used to compare before and after as a way to check if queue was flushed
97
+ const bufferedHeight = this.latestBufferedHeight;
98
+ const pendingBlock = worker.fetchBlock(height);
99
+ const processBlock = async () => {
100
+ var _a;
101
+ try {
102
+ const start = new Date();
103
+ const result = await pendingBlock;
104
+ const end = new Date();
105
+ if (bufferedHeight > this.latestBufferedHeight) {
106
+ logger.debug(`Queue was reset for new DS, discarding fetched blocks`);
107
+ return;
108
+ }
109
+ const waitTime = end.getTime() - start.getTime();
110
+ if (waitTime > 1000) {
111
+ logger.info(`Waiting to fetch block ${height}: ${chalk_1.default.red(`${waitTime}ms`)}`);
112
+ }
113
+ else if (waitTime > 200) {
114
+ logger.info(`Waiting to fetch block ${height}: ${chalk_1.default.yellow(`${waitTime}ms`)}`);
115
+ }
116
+ // logger.info(
117
+ // `worker ${workerIdx} processing block ${height}, fetched blocks: ${await worker.numFetchedBlocks()}, fetching blocks: ${await worker.numFetchingBlocks()}`,
118
+ // );
119
+ this.preProcessBlock(height);
120
+ const { dynamicDsCreated, operationHash, reindexBlockHeight } = await worker.processBlock(height);
121
+ await this.postProcessBlock(height, {
122
+ dynamicDsCreated,
123
+ operationHash: Buffer.from(operationHash, 'base64'),
124
+ reindexBlockHeight,
125
+ });
126
+ }
127
+ catch (e) {
128
+ logger.error(e, `failed to index block at height ${height} ${e.handler ? `${e.handler}(${(_a = e.stack) !== null && _a !== void 0 ? _a : ''})` : ''}`);
129
+ throw e;
130
+ }
131
+ };
132
+ void this.queue.put(processBlock);
133
+ }
134
+ async sampleWorkerStatus() {
135
+ for (const worker of this.workers) {
136
+ const status = await worker.getStatus();
137
+ logger.info(JSON.stringify(status));
138
+ }
139
+ }
140
+ // Getter doesn't seem to cary from abstract class
141
+ get latestBufferedHeight() {
142
+ return this._latestBufferedHeight;
143
+ }
144
+ set latestBufferedHeight(height) {
145
+ super.latestBufferedHeight = height;
146
+ // There is only a single queue with workers so we treat them as the same
147
+ this.eventEmitter.emit(node_core_1.IndexerEvent.BlockQueueSize, {
148
+ value: this.queueSize,
149
+ });
150
+ }
151
+ getNextWorkerIndex() {
152
+ const index = this.taskCounter % this.numWorkers;
153
+ this.taskCounter++;
154
+ return index;
155
+ }
156
+ };
157
+ __decorate([
158
+ (0, schedule_1.Interval)(15000),
159
+ __metadata("design:type", Function),
160
+ __metadata("design:paramtypes", []),
161
+ __metadata("design:returntype", Promise)
162
+ ], WorkerBlockDispatcherService.prototype, "sampleWorkerStatus", null);
163
+ WorkerBlockDispatcherService = __decorate([
164
+ (0, common_1.Injectable)(),
165
+ __metadata("design:paramtypes", [node_core_1.NodeConfig,
166
+ event_emitter_1.EventEmitter2,
167
+ project_service_1.ProjectService])
168
+ ], WorkerBlockDispatcherService);
169
+ exports.WorkerBlockDispatcherService = WorkerBlockDispatcherService;
170
+ //# sourceMappingURL=worker-block-dispatcher.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-block-dispatcher.service.js","sourceRoot":"","sources":["../../../src/indexer/blockDispatcher/worker-block-dispatcher.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2021 OnFinality Limited authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport assert from 'assert';\nimport path from 'path';\nimport { Injectable, OnApplicationShutdown } from '@nestjs/common';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { Interval } from '@nestjs/schedule';\nimport {\n getLogger,\n NodeConfig,\n IndexerEvent,\n Worker,\n AutoQueue,\n} from '@subql/node-core';\nimport chalk from 'chalk';\nimport { last } from 'lodash';\nimport { ProjectService } from '../project.service';\nimport {\n FetchBlock,\n ProcessBlock,\n InitWorker,\n NumFetchedBlocks,\n NumFetchingBlocks,\n GetWorkerStatus,\n} from '../worker/worker';\nimport { BaseBlockDispatcher } from './base-block-dispatcher';\n\nconst logger = getLogger('WorkerBlockDispatcherService');\n\ntype IIndexerWorker = {\n processBlock: ProcessBlock;\n fetchBlock: FetchBlock;\n numFetchedBlocks: NumFetchedBlocks;\n numFetchingBlocks: NumFetchingBlocks;\n getStatus: GetWorkerStatus;\n};\n\ntype IInitIndexerWorker = IIndexerWorker & {\n initWorker: InitWorker;\n};\n\ntype IndexerWorker = IIndexerWorker & {\n terminate: () => Promise<number>;\n};\n\nasync function createIndexerWorker(): Promise<IndexerWorker> {\n const indexerWorker = Worker.create<IInitIndexerWorker>(\n path.resolve(__dirname, '../../../dist/indexer/worker/worker.js'),\n [\n 'initWorker',\n 'processBlock',\n 'fetchBlock',\n 'numFetchedBlocks',\n 'numFetchingBlocks',\n 'getStatus',\n ],\n );\n\n await indexerWorker.initWorker();\n\n return indexerWorker;\n}\n\n@Injectable()\nexport class WorkerBlockDispatcherService\n extends BaseBlockDispatcher<AutoQueue<void>>\n implements OnApplicationShutdown\n{\n private workers: IndexerWorker[];\n private numWorkers: number;\n\n private taskCounter = 0;\n private isShutdown = false;\n\n constructor(\n nodeConfig: NodeConfig,\n eventEmitter: EventEmitter2,\n projectService: ProjectService,\n ) {\n const numWorkers = nodeConfig.workers;\n super(\n nodeConfig,\n eventEmitter,\n projectService,\n new AutoQueue(numWorkers * nodeConfig.batchSize * 2),\n );\n this.numWorkers = numWorkers;\n }\n\n async init(\n onDynamicDsCreated: (height: number) => Promise<void>,\n ): Promise<void> {\n if (this.nodeConfig.unfinalizedBlocks) {\n throw new Error(\n 'Sorry, best block feature is not supported with workers yet.',\n );\n }\n\n this.workers = await Promise.all(\n new Array(this.numWorkers).fill(0).map(() => createIndexerWorker()),\n );\n\n this.onDynamicDsCreated = onDynamicDsCreated;\n\n const blockAmount = await this.projectService.getProcessedBlockCount();\n this.setProcessedBlockCount(blockAmount ?? 0);\n }\n\n async onApplicationShutdown(): Promise<void> {\n this.isShutdown = true;\n // Stop processing blocks\n this.queue.abort();\n\n // Stop all workers\n if (this.workers) {\n await Promise.all(this.workers.map((w) => w.terminate()));\n }\n }\n\n enqueueBlocks(heights: number[]): void {\n if (!heights.length) return;\n logger.info(\n `Enqueing blocks [${heights[0]}...${last(heights)}], total ${\n heights.length\n } blocks`,\n );\n\n // eslint-disable-next-line no-constant-condition\n if (true) {\n /*\n * Load balancing:\n * worker1: 1,2,3\n * worker2: 4,5,6\n */\n const workerIdx = this.getNextWorkerIndex();\n heights.map((height) => this.enqueueBlock(height, workerIdx));\n } else {\n /*\n * Load balancing:\n * worker1: 1,3,5\n * worker2: 2,4,6\n */\n heights.map((height) =>\n this.enqueueBlock(height, this.getNextWorkerIndex()),\n );\n }\n\n this.latestBufferedHeight = last(heights);\n }\n\n private enqueueBlock(height: number, workerIdx: number) {\n if (this.isShutdown) return;\n const worker = this.workers[workerIdx];\n\n assert(worker, `Worker ${workerIdx} not found`);\n\n // Used to compare before and after as a way to check if queue was flushed\n const bufferedHeight = this.latestBufferedHeight;\n const pendingBlock = worker.fetchBlock(height);\n\n const processBlock = async () => {\n try {\n const start = new Date();\n const result = await pendingBlock;\n const end = new Date();\n\n if (bufferedHeight > this.latestBufferedHeight) {\n logger.debug(`Queue was reset for new DS, discarding fetched blocks`);\n return;\n }\n\n const waitTime = end.getTime() - start.getTime();\n if (waitTime > 1000) {\n logger.info(\n `Waiting to fetch block ${height}: ${chalk.red(`${waitTime}ms`)}`,\n );\n } else if (waitTime > 200) {\n logger.info(\n `Waiting to fetch block ${height}: ${chalk.yellow(\n `${waitTime}ms`,\n )}`,\n );\n }\n\n // logger.info(\n // `worker ${workerIdx} processing block ${height}, fetched blocks: ${await worker.numFetchedBlocks()}, fetching blocks: ${await worker.numFetchingBlocks()}`,\n // );\n\n this.preProcessBlock(height);\n\n const { dynamicDsCreated, operationHash, reindexBlockHeight } =\n await worker.processBlock(height);\n\n await this.postProcessBlock(height, {\n dynamicDsCreated,\n operationHash: Buffer.from(operationHash, 'base64'),\n reindexBlockHeight,\n });\n } catch (e) {\n logger.error(\n e,\n `failed to index block at height ${height} ${\n e.handler ? `${e.handler}(${e.stack ?? ''})` : ''\n }`,\n );\n throw e;\n }\n };\n\n void this.queue.put(processBlock);\n }\n\n @Interval(15000)\n async sampleWorkerStatus(): Promise<void> {\n for (const worker of this.workers) {\n const status = await worker.getStatus();\n logger.info(JSON.stringify(status));\n }\n }\n\n // Getter doesn't seem to cary from abstract class\n get latestBufferedHeight(): number {\n return this._latestBufferedHeight;\n }\n\n set latestBufferedHeight(height: number) {\n super.latestBufferedHeight = height;\n // There is only a single queue with workers so we treat them as the same\n this.eventEmitter.emit(IndexerEvent.BlockQueueSize, {\n value: this.queueSize,\n });\n }\n\n private getNextWorkerIndex(): number {\n const index = this.taskCounter % this.numWorkers;\n\n this.taskCounter++;\n\n return index;\n }\n}\n"]}
@@ -15,6 +15,7 @@ export declare class DynamicDsService {
15
15
  constructor(dsProcessorService: DsProcessorService, project: SubqueryProject);
16
16
  init(metaDataRepo: MetadataRepo): void;
17
17
  private _datasources;
18
+ resetDynamicDatasource(targetHeight: number, tx: Transaction): Promise<void>;
18
19
  createDynamicDatasource(params: DatasourceParams, tx: Transaction): Promise<SubqlProjectDs>;
19
20
  getDynamicDatasources(): Promise<SubqlProjectDs[]>;
20
21
  deleteTempDsRecords(blockHeight: number): void;
@@ -33,6 +33,14 @@ let DynamicDsService = class DynamicDsService {
33
33
  init(metaDataRepo) {
34
34
  this.metaDataRepo = metaDataRepo;
35
35
  }
36
+ async resetDynamicDatasource(targetHeight, tx) {
37
+ const dynamicDs = await this.getDynamicDatasourceParams();
38
+ if (dynamicDs.length !== 0) {
39
+ const filteredDs = dynamicDs.filter((ds) => ds.startBlock <= targetHeight);
40
+ const dsRecords = JSON.stringify(filteredDs);
41
+ await this.metaDataRepo.upsert({ key: METADATA_KEY, value: dsRecords }, { transaction: tx });
42
+ }
43
+ }
36
44
  async createDynamicDatasource(params, tx) {
37
45
  try {
38
46
  const ds = await this.getDatasource(params);
@@ -65,22 +73,21 @@ let DynamicDsService = class DynamicDsService {
65
73
  delete this.tempDsRecords[TEMP_DS_PREFIX + blockHeight];
66
74
  }
67
75
  async getDynamicDatasourceParams(blockHeight) {
68
- var _a;
76
+ var _a, _b, _c;
69
77
  (0, assert_1.default)(this.metaDataRepo, `Model _metadata does not exist`);
70
78
  const record = await this.metaDataRepo.findByPk(METADATA_KEY);
71
- let results = record === null || record === void 0 ? void 0 : record.value;
72
- if (!results || typeof results !== 'string') {
73
- if (blockHeight !== undefined) {
74
- results = (_a = this.tempDsRecords) === null || _a === void 0 ? void 0 : _a[TEMP_DS_PREFIX + blockHeight];
75
- if (!results || typeof results !== 'string') {
76
- return [];
77
- }
78
- }
79
- else {
80
- return [];
79
+ let results = [];
80
+ const metaResults = JSON.parse((_a = record === null || record === void 0 ? void 0 : record.value) !== null && _a !== void 0 ? _a : '[]');
81
+ if (metaResults.length) {
82
+ results = [...metaResults];
83
+ }
84
+ if (blockHeight !== undefined) {
85
+ const tempResults = JSON.parse((_c = (_b = this.tempDsRecords) === null || _b === void 0 ? void 0 : _b[TEMP_DS_PREFIX + blockHeight]) !== null && _c !== void 0 ? _c : '[]');
86
+ if (tempResults.length) {
87
+ results = (0, lodash_1.unionWith)(results, tempResults, lodash_1.isEqual);
81
88
  }
82
89
  }
83
- return JSON.parse(results);
90
+ return results;
84
91
  }
85
92
  async saveDynamicDatasourceParams(dsParams, tx) {
86
93
  const existing = await this.getDynamicDatasourceParams(dsParams.startBlock);