@subql/node-ethereum 3.3.6 → 3.3.7-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/configure/NodeConfig.d.ts +2 -0
  4. package/dist/configure/NodeConfig.js +3 -0
  5. package/dist/configure/NodeConfig.js.map +1 -1
  6. package/dist/ethereum/api.ethereum.d.ts +2 -1
  7. package/dist/ethereum/api.ethereum.js +5 -2
  8. package/dist/ethereum/api.ethereum.js.map +1 -1
  9. package/dist/ethereum/ethers/celo/celo-json-rpc-batch-provider.spec.js +1 -1
  10. package/dist/ethereum/ethers/celo/celo-json-rpc-batch-provider.spec.js.map +1 -1
  11. package/dist/ethereum/ethers/celo/celo-json-rpc-provider.spec.js +1 -1
  12. package/dist/ethereum/ethers/celo/celo-json-rpc-provider.spec.js.map +1 -1
  13. package/dist/ethereum/ethers/celo/celo-ws-provider.spec.js +1 -1
  14. package/dist/ethereum/ethers/celo/celo-ws-provider.spec.js.map +1 -1
  15. package/dist/indexer/blockDispatcher/block-dispatcher.service.d.ts +2 -2
  16. package/dist/indexer/blockDispatcher/block-dispatcher.service.js +3 -4
  17. package/dist/indexer/blockDispatcher/block-dispatcher.service.js.map +1 -1
  18. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.d.ts +2 -2
  19. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js +3 -4
  20. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js.map +1 -1
  21. package/dist/indexer/fetch.module.js +3 -4
  22. package/dist/indexer/fetch.module.js.map +1 -1
  23. package/dist/indexer/project.service.d.ts +2 -1
  24. package/dist/indexer/project.service.js +3 -0
  25. package/dist/indexer/project.service.js.map +1 -1
  26. package/dist/indexer/unfinalizedBlocks.service.d.ts +19 -1
  27. package/dist/indexer/unfinalizedBlocks.service.js +84 -1
  28. package/dist/indexer/unfinalizedBlocks.service.js.map +1 -1
  29. package/dist/indexer/unfinalizedBlocks.service.spec.d.ts +1 -0
  30. package/dist/indexer/unfinalizedBlocks.service.spec.js +151 -0
  31. package/dist/indexer/unfinalizedBlocks.service.spec.js.map +1 -0
  32. package/dist/yargs.js +8 -2
  33. package/dist/yargs.js.map +1 -1
  34. package/package.json +4 -3
@@ -14,6 +14,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.UnfinalizedBlocksService = exports.blockToHeader = void 0;
15
15
  const common_1 = require("@nestjs/common");
16
16
  const node_core_1 = require("@subql/node-core");
17
+ const lodash_1 = require("lodash");
18
+ const NodeConfig_1 = require("../configure/NodeConfig");
19
+ const logger = (0, node_core_1.getLogger)('UnfinalizedBlocksService');
17
20
  function blockToHeader(block) {
18
21
  return {
19
22
  blockHeight: block.number,
@@ -24,8 +27,82 @@ function blockToHeader(block) {
24
27
  exports.blockToHeader = blockToHeader;
25
28
  let UnfinalizedBlocksService = class UnfinalizedBlocksService extends node_core_1.BaseUnfinalizedBlocksService {
26
29
  constructor(apiService, nodeConfig, storeCache) {
27
- super(nodeConfig, storeCache);
30
+ super(new NodeConfig_1.EthereumNodeConfig(nodeConfig), storeCache);
28
31
  this.apiService = apiService;
32
+ this.startupCheck = true;
33
+ }
34
+ /**
35
+ * @param reindex - the function to reindex back before a fork
36
+ * @param supportsFinalization - If the chain supports the 'finalized' block tag this should be true.
37
+ * */
38
+ async init(reindex, supportsFinalisation) {
39
+ this.supportsFinalization = supportsFinalisation;
40
+ return super.init(reindex);
41
+ }
42
+ /**
43
+ * Checks if a fork has happened, this doesn't find the start of the fork just where it was detected
44
+ * @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
45
+ * */
46
+ async hasForked() {
47
+ if (this.supportsFinalization) {
48
+ return super.hasForked();
49
+ }
50
+ // Startup check helps speed up finding a fork by checking the hash of the last unfinalized block
51
+ if (this.startupCheck) {
52
+ this.startupCheck = false;
53
+ const lastUnfinalized = (0, lodash_1.last)(this.unfinalizedBlocks);
54
+ if (lastUnfinalized) {
55
+ const checkUnfinalized = await this.getHeaderForHeight(lastUnfinalized.blockHeight);
56
+ if (lastUnfinalized.blockHash !== checkUnfinalized.blockHash) {
57
+ return checkUnfinalized;
58
+ }
59
+ }
60
+ }
61
+ if (this.unfinalizedBlocks.length <= 2) {
62
+ return;
63
+ }
64
+ const i = this.unfinalizedBlocks.length - 1;
65
+ const current = this.unfinalizedBlocks[i];
66
+ const parent = this.unfinalizedBlocks[i - 1];
67
+ if (current.parentHash !== parent.blockHash) {
68
+ // We've found a fork now we need to find where the fork happened
69
+ logger.warn(`Block fork detected at ${current.blockHeight}. Parent hash ${current.parentHash} doesn't match indexed parent ${parent.blockHash}.`);
70
+ return current;
71
+ }
72
+ return;
73
+ }
74
+ /**
75
+ * Finds the height before the fork occurred based on the result of hasForked
76
+ * @return (number | undefined) - The block height to rewind to to remove forked data
77
+ **/
78
+ async getLastCorrectFinalizedBlock(forkedHeader) {
79
+ if (this.supportsFinalization) {
80
+ return super.getLastCorrectFinalizedBlock(forkedHeader);
81
+ }
82
+ const bestVerifiableBlocks = this.unfinalizedBlocks.filter(({ blockHeight }) => blockHeight < forkedHeader.blockHeight);
83
+ let checkingHeader = forkedHeader;
84
+ // Work backwards through the blocks until we find a matching hash
85
+ for (const { blockHash, blockHeight } of bestVerifiableBlocks.reverse()) {
86
+ if (blockHash === checkingHeader.blockHash ||
87
+ blockHash === checkingHeader.parentHash) {
88
+ return blockHeight;
89
+ }
90
+ // Get the new parent
91
+ checkingHeader = await this.getHeaderForHash(checkingHeader.parentHash);
92
+ }
93
+ try {
94
+ const poiHeader = await this.findFinalizedUsingPOI(checkingHeader);
95
+ return poiHeader.blockHeight;
96
+ }
97
+ catch (e) {
98
+ if (e.message === node_core_1.POI_NOT_ENABLED_ERROR_MESSAGE) {
99
+ return Math.max(0, forkedHeader.blockHeight -
100
+ this.nodeConfig.blockForkReindex);
101
+ }
102
+ // TODO rewind back 1000+ blocks
103
+ logger.info('Failed to use POI to rewind block');
104
+ throw e;
105
+ }
29
106
  }
30
107
  blockToHeader(block) {
31
108
  return blockToHeader(block);
@@ -43,6 +120,12 @@ let UnfinalizedBlocksService = class UnfinalizedBlocksService extends node_core_
43
120
  return blockToHeader(block);
44
121
  }
45
122
  };
123
+ __decorate([
124
+ (0, node_core_1.profiler)(),
125
+ __metadata("design:type", Function),
126
+ __metadata("design:paramtypes", []),
127
+ __metadata("design:returntype", Promise)
128
+ ], UnfinalizedBlocksService.prototype, "hasForked", null);
46
129
  __decorate([
47
130
  (0, node_core_1.mainThreadOnly)(),
48
131
  __metadata("design:type", Function),
@@ -1 +1 @@
1
- {"version":3,"file":"unfinalizedBlocks.service.js","sourceRoot":"","sources":["../../src/indexer/unfinalizedBlocks.service.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;;;;;;;;;;;AAGnC,2CAA4C;AAC5C,gDAO0B;AAG1B,SAAgB,aAAa,CAAC,KAA2B;IACvD,OAAO;QACL,WAAW,EAAE,KAAK,CAAC,MAAM;QACzB,SAAS,EAAE,KAAK,CAAC,IAAI;QACrB,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC;AACJ,CAAC;AAND,sCAMC;AAGM,IAAM,wBAAwB,GAA9B,MAAM,wBAAyB,SAAQ,wCAA0C;IACtF,YACmB,UAAsB,EACvC,UAAsB,EACtB,UAA6B;QAE7B,KAAK,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAJb,eAAU,GAAV,UAAU,CAAY;IAKzC,CAAC;IAGS,aAAa,CAAC,KAAmB;QACzC,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAGe,AAAN,KAAK,CAAC,gBAAgB;QAC9B,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACrE,OAAO,aAAa,CAAC,cAAc,CAAC,CAAC;IACvC,CAAC;IAGe,AAAN,KAAK,CAAC,gBAAgB,CAAC,IAAY;QAC3C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACrE,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAGe,AAAN,KAAK,CAAC,kBAAkB,CAAC,MAAc;QAC/C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;QACvE,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;CACF,CAAA;AAtBC;IAAC,IAAA,0BAAc,GAAE;;;;6DAGhB;AAGe;IADf,IAAA,0BAAc,GAAE;;;;gEAIhB;AAGe;IADf,IAAA,0BAAc,GAAE;;;;gEAIhB;AAGe;IADf,IAAA,0BAAc,GAAE;;;;kEAIhB;AA9BU,wBAAwB;IADpC,IAAA,mBAAU,GAAE;qCAGoB,sBAAU;QAC3B,sBAAU;QACV,6BAAiB;GAJpB,wBAAwB,CA+BpC;AA/BY,4DAAwB","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Block } from '@ethersproject/abstract-provider';\nimport { Injectable } from '@nestjs/common';\nimport {\n ApiService,\n BaseUnfinalizedBlocksService,\n Header,\n mainThreadOnly,\n NodeConfig,\n StoreCacheService,\n} from '@subql/node-core';\nimport { BlockContent } from './types';\n\nexport function blockToHeader(block: BlockContent | Block): Header {\n return {\n blockHeight: block.number,\n blockHash: block.hash,\n parentHash: block.parentHash,\n };\n}\n\n@Injectable()\nexport class UnfinalizedBlocksService extends BaseUnfinalizedBlocksService<BlockContent> {\n constructor(\n private readonly apiService: ApiService,\n nodeConfig: NodeConfig,\n storeCache: StoreCacheService,\n ) {\n super(nodeConfig, storeCache);\n }\n\n @mainThreadOnly()\n protected blockToHeader(block: BlockContent): Header {\n return blockToHeader(block);\n }\n\n @mainThreadOnly()\n protected async getFinalizedHead(): Promise<Header> {\n const finalizedBlock = await this.apiService.api.getFinalizedBlock();\n return blockToHeader(finalizedBlock);\n }\n\n @mainThreadOnly()\n protected async getHeaderForHash(hash: string): Promise<Header> {\n const block = await this.apiService.api.getBlockByHeightOrHash(hash);\n return blockToHeader(block);\n }\n\n @mainThreadOnly()\n protected async getHeaderForHeight(height: number): Promise<Header> {\n const block = await this.apiService.api.getBlockByHeightOrHash(height);\n return blockToHeader(block);\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-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { Block } from '@ethersproject/abstract-provider';\nimport { Injectable } from '@nestjs/common';\nimport {\n ApiService,\n BaseUnfinalizedBlocksService,\n Header,\n mainThreadOnly,\n NodeConfig,\n StoreCacheService,\n getLogger,\n profiler,\n POI_NOT_ENABLED_ERROR_MESSAGE,\n} from '@subql/node-core';\nimport { EthereumBlock } from '@subql/types-ethereum';\nimport { last } from 'lodash';\nimport { EthereumNodeConfig } from '../configure/NodeConfig';\nimport { BlockContent } from './types';\n\nconst logger = getLogger('UnfinalizedBlocksService');\n\nexport function blockToHeader(block: BlockContent | Block): Header {\n return {\n blockHeight: block.number,\n blockHash: block.hash,\n parentHash: block.parentHash,\n };\n}\n\n@Injectable()\nexport class UnfinalizedBlocksService extends BaseUnfinalizedBlocksService<EthereumBlock> {\n private supportsFinalization?: boolean;\n private startupCheck = true;\n\n constructor(\n private readonly apiService: ApiService,\n nodeConfig: NodeConfig,\n storeCache: StoreCacheService,\n ) {\n super(new EthereumNodeConfig(nodeConfig), storeCache);\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 async init(\n reindex: (targetHeight: number) => Promise<void>,\n supportsFinalisation?: boolean,\n ): Promise<number | 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 = await this.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<number | 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 { blockHash, blockHeight } of bestVerifiableBlocks.reverse()) {\n if (\n blockHash === checkingHeader.blockHash ||\n blockHash === checkingHeader.parentHash\n ) {\n return blockHeight;\n }\n\n // Get the new parent\n checkingHeader = await this.getHeaderForHash(checkingHeader.parentHash);\n }\n\n try {\n const poiHeader = await this.findFinalizedUsingPOI(checkingHeader);\n return poiHeader.blockHeight;\n } catch (e) {\n if (e.message === POI_NOT_ENABLED_ERROR_MESSAGE) {\n return Math.max(\n 0,\n forkedHeader.blockHeight -\n (this.nodeConfig as EthereumNodeConfig).blockForkReindex,\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 @mainThreadOnly()\n protected blockToHeader(block: BlockContent): Header {\n return blockToHeader(block);\n }\n\n @mainThreadOnly()\n protected async getFinalizedHead(): Promise<Header> {\n const finalizedBlock = await this.apiService.api.getFinalizedBlock();\n return blockToHeader(finalizedBlock);\n }\n\n @mainThreadOnly()\n protected async getHeaderForHash(hash: string): Promise<Header> {\n const block = await this.apiService.api.getBlockByHeightOrHash(hash);\n return blockToHeader(block);\n }\n\n @mainThreadOnly()\n protected async getHeaderForHeight(height: number): Promise<Header> {\n const block = await this.apiService.api.getBlockByHeightOrHash(height);\n return blockToHeader(block);\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ // Copyright 2020-2023 SubQuery Pte Ltd authors & contributors
3
+ // SPDX-License-Identifier: GPL-3.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ const bytes_1 = require("@ethersproject/bytes");
6
+ const node_core_1 = require("@subql/node-core");
7
+ const unfinalizedBlocks_service_1 = require("./unfinalizedBlocks.service");
8
+ // Adds 0 padding so we can convert to POI block
9
+ const hexify = (input) => (0, bytes_1.hexZeroPad)(input, 4);
10
+ const makeHeader = (height, finalized) => ({
11
+ blockHeight: height,
12
+ blockHash: hexify(`0xABC${height}${finalized ? 'f' : ''}`),
13
+ parentHash: hexify(`0xABC${height - 1}${finalized ? 'f' : ''}`),
14
+ });
15
+ const getMockApi = () => {
16
+ return {
17
+ api: {
18
+ getBlockByHeightOrHash: (hash) => {
19
+ const num = typeof hash === 'number'
20
+ ? hash
21
+ : Number(hash
22
+ .toString()
23
+ .replace('0x', '')
24
+ .replace('ABC', '')
25
+ .replace('f', ''));
26
+ return Promise.resolve({
27
+ number: num,
28
+ hash: typeof hash === 'number' ? hexify(`0xABC${hash}f`) : hash,
29
+ parentHash: hexify(`0xABC${num - 1}f`),
30
+ });
31
+ },
32
+ getFinalizedBlock: jest.fn(() => ({
33
+ number: 110,
34
+ hash: '0xABC110f',
35
+ parentHash: '0xABC109f',
36
+ })),
37
+ },
38
+ };
39
+ };
40
+ function getMockMetadata() {
41
+ const data = {};
42
+ return {
43
+ upsert: ({ key, value }) => (data[key] = value),
44
+ findOne: ({ where: { key } }) => ({ value: data[key] }),
45
+ findByPk: (key) => data[key],
46
+ find: (key) => data[key],
47
+ };
48
+ }
49
+ function mockStoreCache() {
50
+ return {
51
+ metadata: new node_core_1.CacheMetadataModel(getMockMetadata()),
52
+ poi: {
53
+ getPoiBlocksBefore: jest.fn(() => [
54
+ node_core_1.PoiBlock.create(99, hexify('0xABC99f'), new Uint8Array(), ''),
55
+ ]),
56
+ },
57
+ };
58
+ }
59
+ describe('UnfinalizedBlockService', () => {
60
+ let unfinalizedBlocks;
61
+ let storeCache;
62
+ beforeEach(() => {
63
+ storeCache = mockStoreCache();
64
+ unfinalizedBlocks = new unfinalizedBlocks_service_1.UnfinalizedBlocksService(getMockApi(), new node_core_1.NodeConfig({
65
+ unfinalizedBlocks: true,
66
+ blockForkReindex: 1000,
67
+ }), storeCache);
68
+ });
69
+ it('handles a block fork', async () => {
70
+ await unfinalizedBlocks.init(jest.fn());
71
+ unfinalizedBlocks._unfinalizedBlocks = [
72
+ makeHeader(100),
73
+ makeHeader(101),
74
+ makeHeader(102),
75
+ makeHeader(103, true),
76
+ makeHeader(104),
77
+ makeHeader(105),
78
+ makeHeader(106),
79
+ makeHeader(107),
80
+ makeHeader(108),
81
+ makeHeader(109),
82
+ makeHeader(110),
83
+ ];
84
+ const rewind = await unfinalizedBlocks.processUnfinalizedBlockHeader(makeHeader(111, true));
85
+ expect(rewind).toEqual(103);
86
+ });
87
+ it('uses POI blocks if there are not enough cached unfinalized blocks', async () => {
88
+ await unfinalizedBlocks.init(jest.fn());
89
+ unfinalizedBlocks._unfinalizedBlocks = [
90
+ makeHeader(100),
91
+ makeHeader(101),
92
+ makeHeader(102),
93
+ makeHeader(103),
94
+ makeHeader(104),
95
+ makeHeader(105),
96
+ makeHeader(106),
97
+ makeHeader(107),
98
+ makeHeader(108),
99
+ makeHeader(109),
100
+ makeHeader(110),
101
+ ];
102
+ const spy = jest.spyOn(storeCache.poi, 'getPoiBlocksBefore');
103
+ const rewind = await unfinalizedBlocks.processUnfinalizedBlockHeader(makeHeader(111, true));
104
+ expect(rewind).toEqual(99);
105
+ expect(spy).toHaveBeenCalled();
106
+ });
107
+ // The finalized block is after the cached unfinalized blocks, they should be rechecked
108
+ it('startup, correctly checks for forks after cached unfinalized blocks', async () => {
109
+ storeCache.metadata.set(node_core_1.METADATA_UNFINALIZED_BLOCKS_KEY, JSON.stringify([
110
+ makeHeader(99, true),
111
+ makeHeader(100),
112
+ makeHeader(101),
113
+ ]));
114
+ storeCache.metadata.set(node_core_1.METADATA_LAST_FINALIZED_PROCESSED_KEY, 99);
115
+ const rewind = jest.fn();
116
+ await unfinalizedBlocks.init(rewind);
117
+ // It should fall back to poi in this case
118
+ expect(rewind).toHaveBeenCalledWith(99);
119
+ });
120
+ it('startup, correctly checks for forks within cached unfinalized blocks', async () => {
121
+ storeCache.metadata.set(node_core_1.METADATA_UNFINALIZED_BLOCKS_KEY, JSON.stringify([
122
+ makeHeader(110),
123
+ makeHeader(111),
124
+ makeHeader(112),
125
+ ]));
126
+ storeCache.metadata.set(node_core_1.METADATA_LAST_FINALIZED_PROCESSED_KEY, 109);
127
+ const rewind = jest.fn();
128
+ await unfinalizedBlocks.init(rewind);
129
+ // It should fall back to poi in this case
130
+ expect(rewind).toHaveBeenCalledWith(99);
131
+ });
132
+ it('doesnt throw if there are no unfinalized blocks on startup', async () => {
133
+ storeCache.metadata.set(node_core_1.METADATA_LAST_FINALIZED_PROCESSED_KEY, 109);
134
+ await expect(unfinalizedBlocks.init(jest.fn())).resolves.not.toThrow();
135
+ });
136
+ it('rewinds using blockForkReindex value if poi is not enabled', async () => {
137
+ // Do this to "disable" poi
138
+ storeCache.poi = null;
139
+ storeCache.metadata.set(node_core_1.METADATA_UNFINALIZED_BLOCKS_KEY, JSON.stringify([
140
+ makeHeader(110),
141
+ makeHeader(111),
142
+ makeHeader(112),
143
+ ]));
144
+ storeCache.metadata.set(node_core_1.METADATA_LAST_FINALIZED_PROCESSED_KEY, 109);
145
+ const rewind = jest.fn();
146
+ await unfinalizedBlocks.init(rewind);
147
+ // It should fall back to poi in this case
148
+ expect(rewind).toHaveBeenCalledWith(0);
149
+ });
150
+ });
151
+ //# sourceMappingURL=unfinalizedBlocks.service.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unfinalizedBlocks.service.spec.js","sourceRoot":"","sources":["../../src/indexer/unfinalizedBlocks.service.spec.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { hexZeroPad } from '@ethersproject/bytes';\nimport {\n ApiService,\n CacheMetadataModel,\n Header,\n NodeConfig,\n PoiBlock,\n StoreCacheService,\n METADATA_UNFINALIZED_BLOCKS_KEY,\n METADATA_LAST_FINALIZED_PROCESSED_KEY,\n} from '@subql/node-core';\nimport { EthereumNodeConfig } from '../configure/NodeConfig';\nimport { UnfinalizedBlocksService } from './unfinalizedBlocks.service';\n\n// Adds 0 padding so we can convert to POI block\nconst hexify = (input: string) => hexZeroPad(input, 4);\n\nconst makeHeader = (height: number, finalized?: boolean): Header => ({\n blockHeight: height,\n blockHash: hexify(`0xABC${height}${finalized ? 'f' : ''}`),\n parentHash: hexify(`0xABC${height - 1}${finalized ? 'f' : ''}`),\n});\n\nconst getMockApi = (): ApiService => {\n return {\n api: {\n getBlockByHeightOrHash: (hash: string | number) => {\n const num =\n typeof hash === 'number'\n ? hash\n : Number(\n hash\n .toString()\n .replace('0x', '')\n .replace('ABC', '')\n .replace('f', ''),\n );\n return Promise.resolve({\n number: num,\n hash: typeof hash === 'number' ? hexify(`0xABC${hash}f`) : hash,\n parentHash: hexify(`0xABC${num - 1}f`),\n });\n },\n getFinalizedBlock: jest.fn(() => ({\n number: 110,\n hash: '0xABC110f',\n parentHash: '0xABC109f',\n })),\n },\n } as any;\n};\n\nfunction getMockMetadata(): any {\n const data: Record<string, any> = {};\n return {\n upsert: ({ key, value }: any) => (data[key] = value),\n findOne: ({ where: { key } }: any) => ({ value: data[key] }),\n findByPk: (key: string) => data[key],\n find: (key: string) => data[key],\n } as any;\n}\n\nfunction mockStoreCache(): StoreCacheService {\n return {\n metadata: new CacheMetadataModel(getMockMetadata()),\n poi: {\n getPoiBlocksBefore: jest.fn(() => [\n PoiBlock.create(99, hexify('0xABC99f'), new Uint8Array(), ''),\n ]),\n },\n } as any as StoreCacheService;\n}\n\ndescribe('UnfinalizedBlockService', () => {\n let unfinalizedBlocks: UnfinalizedBlocksService;\n let storeCache: StoreCacheService;\n\n beforeEach(() => {\n storeCache = mockStoreCache();\n\n unfinalizedBlocks = new UnfinalizedBlocksService(\n getMockApi(),\n new NodeConfig({\n unfinalizedBlocks: true,\n blockForkReindex: 1000,\n } as any) as EthereumNodeConfig,\n storeCache,\n );\n });\n\n it('handles a block fork', async () => {\n await unfinalizedBlocks.init(jest.fn());\n\n (unfinalizedBlocks as any)._unfinalizedBlocks = [\n makeHeader(100),\n makeHeader(101),\n makeHeader(102),\n makeHeader(103, true), // Where the fork started\n makeHeader(104),\n makeHeader(105),\n makeHeader(106),\n makeHeader(107),\n makeHeader(108),\n makeHeader(109),\n makeHeader(110),\n ];\n\n const rewind = await unfinalizedBlocks.processUnfinalizedBlockHeader(\n makeHeader(111, true),\n );\n\n expect(rewind).toEqual(103);\n });\n\n it('uses POI blocks if there are not enough cached unfinalized blocks', async () => {\n await unfinalizedBlocks.init(jest.fn());\n\n (unfinalizedBlocks as any)._unfinalizedBlocks = [\n makeHeader(100),\n makeHeader(101),\n makeHeader(102),\n makeHeader(103),\n makeHeader(104),\n makeHeader(105),\n makeHeader(106),\n makeHeader(107),\n makeHeader(108),\n makeHeader(109),\n makeHeader(110),\n ];\n\n const spy = jest.spyOn(storeCache.poi as any, 'getPoiBlocksBefore');\n\n const rewind = await unfinalizedBlocks.processUnfinalizedBlockHeader(\n makeHeader(111, true),\n );\n\n expect(rewind).toEqual(99);\n expect(spy).toHaveBeenCalled();\n });\n\n // The finalized block is after the cached unfinalized blocks, they should be rechecked\n it('startup, correctly checks for forks after cached unfinalized blocks', async () => {\n storeCache.metadata.set(\n METADATA_UNFINALIZED_BLOCKS_KEY,\n JSON.stringify(<Header[]>[\n makeHeader(99, true),\n makeHeader(100),\n makeHeader(101),\n ]),\n );\n\n storeCache.metadata.set(METADATA_LAST_FINALIZED_PROCESSED_KEY, 99);\n\n const rewind = jest.fn();\n\n await unfinalizedBlocks.init(rewind);\n\n // It should fall back to poi in this case\n expect(rewind).toHaveBeenCalledWith(99);\n });\n\n it('startup, correctly checks for forks within cached unfinalized blocks', async () => {\n storeCache.metadata.set(\n METADATA_UNFINALIZED_BLOCKS_KEY,\n JSON.stringify(<Header[]>[\n makeHeader(110),\n makeHeader(111),\n makeHeader(112),\n ]),\n );\n\n storeCache.metadata.set(METADATA_LAST_FINALIZED_PROCESSED_KEY, 109);\n\n const rewind = jest.fn();\n\n await unfinalizedBlocks.init(rewind);\n\n // It should fall back to poi in this case\n expect(rewind).toHaveBeenCalledWith(99);\n });\n\n it('doesnt throw if there are no unfinalized blocks on startup', async () => {\n storeCache.metadata.set(METADATA_LAST_FINALIZED_PROCESSED_KEY, 109);\n\n await expect(unfinalizedBlocks.init(jest.fn())).resolves.not.toThrow();\n });\n\n it('rewinds using blockForkReindex value if poi is not enabled', async () => {\n // Do this to \"disable\" poi\n (storeCache as any).poi = null;\n\n storeCache.metadata.set(\n METADATA_UNFINALIZED_BLOCKS_KEY,\n JSON.stringify(<Header[]>[\n makeHeader(110),\n makeHeader(111),\n makeHeader(112),\n ]),\n );\n\n storeCache.metadata.set(METADATA_LAST_FINALIZED_PROCESSED_KEY, 109);\n\n const rewind = jest.fn();\n\n await unfinalizedBlocks.init(rewind);\n\n // It should fall back to poi in this case\n expect(rewind).toHaveBeenCalledWith(0);\n });\n});\n"]}
package/dist/yargs.js CHANGED
@@ -26,10 +26,16 @@ exports.yargsOptions = (0, yargs_1.yargsBuilder)({
26
26
  runOptions: {
27
27
  'block-confirmations': {
28
28
  demandOption: false,
29
- default: 20,
30
- describe: 'The number of blocks behind the head to be considered finalized, this has no effect with Ethereum',
29
+ default: 200,
30
+ describe: 'The number of blocks behind the head to be considered finalized for networks without deterministic finalisation such as Polygon POS',
31
31
  type: 'number',
32
32
  },
33
+ 'block-fork-reindex': {
34
+ demandOption: false,
35
+ default: 1000,
36
+ type: 'number',
37
+ describe: 'The number of blocks to reindex if a fork happens before cached unfinalized blocks and POI is not enabled.',
38
+ },
33
39
  },
34
40
  });
35
41
  //# sourceMappingURL=yargs.js.map
package/dist/yargs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"yargs.js","sourceRoot":"","sources":["../src/yargs.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;;AAEnC,kDAAsD;AAEzC,QAAA,YAAY,GAAG,IAAA,oBAAY,EAAC;IACvC,WAAW,EAAE,GAAG,EAAE;QAChB,4EAA4E;QAC5E,8DAA8D;QAC9D,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC9D,OAAO,WAAW,EAAE,CAAC;IACvB,CAAC;IACD,cAAc,EAAE,GAAG,EAAE;QACnB,4EAA4E;QAC5E,8DAA8D;QAC9D,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAAC;QACpE,OAAO,cAAc,EAAE,CAAC;IAC1B,CAAC;IACD,WAAW,EAAE,CAAC,YAAoB,EAAE,EAAE;QACpC,4EAA4E;QAC5E,8DAA8D;QAC9D,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC9D,OAAO,WAAW,CAAC,YAAY,CAAC,CAAC;IACnC,CAAC;IACD,UAAU,EAAE;QACV,qBAAqB,EAAE;YACrB,YAAY,EAAE,KAAK;YACnB,OAAO,EAAE,EAAE;YACX,QAAQ,EACN,mGAAmG;YACrG,IAAI,EAAE,QAAQ;SACf;KACF;CACF,CAAC,CAAC","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { yargsBuilder } from '@subql/node-core/yargs';\n\nexport const yargsOptions = yargsBuilder({\n initTesting: () => {\n // lazy import to make sure logger is instantiated before all other services\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { testingInit } = require('./subcommands/testing.init');\n return testingInit();\n },\n initForceClean: () => {\n // lazy import to make sure logger is instantiated before all other services\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { forceCleanInit } = require('./subcommands/forceClean.init');\n return forceCleanInit();\n },\n initReindex: (targetHeight: number) => {\n // lazy import to make sure logger is instantiated before all other services\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { reindexInit } = require('./subcommands/reindex.init');\n return reindexInit(targetHeight);\n },\n runOptions: {\n 'block-confirmations': {\n demandOption: false,\n default: 20,\n describe:\n 'The number of blocks behind the head to be considered finalized, this has no effect with Ethereum',\n type: 'number',\n },\n },\n});\n"]}
1
+ {"version":3,"file":"yargs.js","sourceRoot":"","sources":["../src/yargs.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mCAAmC;;;AAEnC,kDAAsD;AAEzC,QAAA,YAAY,GAAG,IAAA,oBAAY,EAAC;IACvC,WAAW,EAAE,GAAG,EAAE;QAChB,4EAA4E;QAC5E,8DAA8D;QAC9D,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC9D,OAAO,WAAW,EAAE,CAAC;IACvB,CAAC;IACD,cAAc,EAAE,GAAG,EAAE;QACnB,4EAA4E;QAC5E,8DAA8D;QAC9D,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAAC;QACpE,OAAO,cAAc,EAAE,CAAC;IAC1B,CAAC;IACD,WAAW,EAAE,CAAC,YAAoB,EAAE,EAAE;QACpC,4EAA4E;QAC5E,8DAA8D;QAC9D,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC9D,OAAO,WAAW,CAAC,YAAY,CAAC,CAAC;IACnC,CAAC;IACD,UAAU,EAAE;QACV,qBAAqB,EAAE;YACrB,YAAY,EAAE,KAAK;YACnB,OAAO,EAAE,GAAG;YACZ,QAAQ,EACN,qIAAqI;YACvI,IAAI,EAAE,QAAQ;SACf;QACD,oBAAoB,EAAE;YACpB,YAAY,EAAE,KAAK;YACnB,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,QAAQ;YACd,QAAQ,EACN,4GAA4G;SAC/G;KACF;CACF,CAAC,CAAC","sourcesContent":["// Copyright 2020-2023 SubQuery Pte Ltd authors & contributors\n// SPDX-License-Identifier: GPL-3.0\n\nimport { yargsBuilder } from '@subql/node-core/yargs';\n\nexport const yargsOptions = yargsBuilder({\n initTesting: () => {\n // lazy import to make sure logger is instantiated before all other services\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { testingInit } = require('./subcommands/testing.init');\n return testingInit();\n },\n initForceClean: () => {\n // lazy import to make sure logger is instantiated before all other services\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { forceCleanInit } = require('./subcommands/forceClean.init');\n return forceCleanInit();\n },\n initReindex: (targetHeight: number) => {\n // lazy import to make sure logger is instantiated before all other services\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { reindexInit } = require('./subcommands/reindex.init');\n return reindexInit(targetHeight);\n },\n runOptions: {\n 'block-confirmations': {\n demandOption: false,\n default: 200,\n describe:\n 'The number of blocks behind the head to be considered finalized for networks without deterministic finalisation such as Polygon POS',\n type: 'number',\n },\n 'block-fork-reindex': {\n demandOption: false,\n default: 1000,\n type: 'number',\n describe:\n 'The number of blocks to reindex if a fork happens before cached unfinalized blocks and POI is not enabled.',\n },\n },\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subql/node-ethereum",
3
- "version": "3.3.6",
3
+ "version": "3.3.7-0",
4
4
  "description": "",
5
5
  "author": "Ian He",
6
6
  "license": "GPL-3.0",
@@ -27,7 +27,7 @@
27
27
  "@nestjs/schedule": "^3.0.1",
28
28
  "@subql/common": "^3.3.0",
29
29
  "@subql/common-ethereum": "3.1.0",
30
- "@subql/node-core": "^6.4.2",
30
+ "@subql/node-core": "^7.0.0",
31
31
  "@subql/testing": "^2.0.2",
32
32
  "@subql/types-ethereum": "3.2.0",
33
33
  "cacheable-lookup": "6",
@@ -65,5 +65,6 @@
65
65
  "files": [
66
66
  "/dist",
67
67
  "/bin"
68
- ]
68
+ ],
69
+ "stableVersion": "3.3.6"
69
70
  }