@subql/node-ethereum 1.10.1-3 → 2.0.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 (143) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +3 -2
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/configure/SubqueryProject.d.ts +9 -11
  5. package/dist/configure/SubqueryProject.js +19 -9
  6. package/dist/configure/SubqueryProject.js.map +1 -1
  7. package/dist/configure/configure.module.js +5 -7
  8. package/dist/configure/configure.module.js.map +1 -1
  9. package/dist/ethereum/api.connection.d.ts +11 -0
  10. package/dist/ethereum/api.connection.js +27 -0
  11. package/dist/ethereum/api.connection.js.map +1 -0
  12. package/dist/ethereum/api.ethereum.d.ts +18 -5
  13. package/dist/ethereum/api.ethereum.js +135 -43
  14. package/dist/ethereum/api.ethereum.js.map +1 -1
  15. package/dist/ethereum/api.service.ethereum.d.ts +11 -3
  16. package/dist/ethereum/api.service.ethereum.js +68 -18
  17. package/dist/ethereum/api.service.ethereum.js.map +1 -1
  18. package/dist/ethereum/api.service.ethereum.test.d.ts +1 -0
  19. package/dist/ethereum/api.service.ethereum.test.js +73 -0
  20. package/dist/ethereum/api.service.ethereum.test.js.map +1 -0
  21. package/dist/ethereum/block.ethereum.d.ts +1 -1
  22. package/dist/ethereum/block.ethereum.js +10 -12
  23. package/dist/ethereum/block.ethereum.js.map +1 -1
  24. package/dist/ethereum/ethers/json-rpc-batch-provider.d.ts +21 -0
  25. package/dist/ethereum/ethers/json-rpc-batch-provider.js +114 -0
  26. package/dist/ethereum/ethers/json-rpc-batch-provider.js.map +1 -0
  27. package/dist/ethereum/ethers/json-rpc-provider.d.ts +7 -0
  28. package/dist/ethereum/ethers/json-rpc-provider.js +68 -0
  29. package/dist/ethereum/ethers/json-rpc-provider.js.map +1 -0
  30. package/dist/ethereum/ethers/web/_version.d.ts +1 -0
  31. package/dist/ethereum/ethers/web/_version.js +6 -0
  32. package/dist/ethereum/ethers/web/_version.js.map +1 -0
  33. package/dist/ethereum/ethers/web/geturl.d.ts +3 -0
  34. package/dist/ethereum/ethers/web/geturl.js +116 -0
  35. package/dist/ethereum/ethers/web/geturl.js.map +1 -0
  36. package/dist/ethereum/ethers/web/index.d.ts +49 -0
  37. package/dist/ethereum/ethers/web/index.js +437 -0
  38. package/dist/ethereum/ethers/web/index.js.map +1 -0
  39. package/dist/ethereum/ethers/web/types.d.ts +26 -0
  40. package/dist/ethereum/ethers/web/types.js +4 -0
  41. package/dist/ethereum/ethers/web/types.js.map +1 -0
  42. package/dist/ethereum/safe-api.d.ts +34 -0
  43. package/dist/ethereum/safe-api.js +114 -0
  44. package/dist/ethereum/safe-api.js.map +1 -0
  45. package/dist/ethereum/utils.ethereum.d.ts +1 -1
  46. package/dist/ethereum/utils.ethereum.js +22 -87
  47. package/dist/ethereum/utils.ethereum.js.map +1 -1
  48. package/dist/indexer/blockDispatcher/block-dispatcher.service.d.ts +17 -0
  49. package/dist/indexer/blockDispatcher/block-dispatcher.service.js +55 -0
  50. package/dist/indexer/blockDispatcher/block-dispatcher.service.js.map +1 -0
  51. package/dist/indexer/blockDispatcher/ethereum-block-dispatcher.d.ts +4 -0
  52. package/dist/indexer/blockDispatcher/ethereum-block-dispatcher.js +5 -0
  53. package/dist/indexer/blockDispatcher/ethereum-block-dispatcher.js.map +1 -0
  54. package/dist/indexer/blockDispatcher/index.d.ts +4 -0
  55. package/dist/indexer/blockDispatcher/index.js +10 -0
  56. package/dist/indexer/blockDispatcher/index.js.map +1 -0
  57. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.d.ts +15 -0
  58. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js +88 -0
  59. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js.map +1 -0
  60. package/dist/indexer/dictionary.service.d.ts +1 -0
  61. package/dist/indexer/dictionary.service.js +22 -2
  62. package/dist/indexer/dictionary.service.js.map +1 -1
  63. package/dist/indexer/ds-processor.service.d.ts +1 -1
  64. package/dist/indexer/ds-processor.service.js +4 -0
  65. package/dist/indexer/ds-processor.service.js.map +1 -1
  66. package/dist/indexer/dynamic-ds.service.d.ts +3 -19
  67. package/dist/indexer/dynamic-ds.service.js +20 -72
  68. package/dist/indexer/dynamic-ds.service.js.map +1 -1
  69. package/dist/indexer/fetch.module.js +40 -12
  70. package/dist/indexer/fetch.module.js.map +1 -1
  71. package/dist/indexer/fetch.service.d.ts +16 -7
  72. package/dist/indexer/fetch.service.js +188 -78
  73. package/dist/indexer/fetch.service.js.map +1 -1
  74. package/dist/indexer/indexer.manager.d.ts +11 -17
  75. package/dist/indexer/indexer.manager.js +68 -71
  76. package/dist/indexer/indexer.manager.js.map +1 -1
  77. package/dist/indexer/indexer.module.js +32 -8
  78. package/dist/indexer/indexer.module.js.map +1 -1
  79. package/dist/indexer/project.service.d.ts +11 -8
  80. package/dist/indexer/project.service.js +76 -82
  81. package/dist/indexer/project.service.js.map +1 -1
  82. package/dist/indexer/sandbox.service.js +11 -2
  83. package/dist/indexer/sandbox.service.js.map +1 -1
  84. package/dist/indexer/types.d.ts +2 -1
  85. package/dist/indexer/types.js.map +1 -1
  86. package/dist/indexer/unfinalizedBlocks.service.d.ts +36 -0
  87. package/dist/indexer/unfinalizedBlocks.service.js +197 -0
  88. package/dist/indexer/unfinalizedBlocks.service.js.map +1 -0
  89. package/dist/indexer/unfinalizedBlocks.spec.d.ts +1 -0
  90. package/dist/indexer/unfinalizedBlocks.spec.js +195 -0
  91. package/dist/indexer/unfinalizedBlocks.spec.js.map +1 -0
  92. package/dist/indexer/worker/worker.d.ts +22 -6
  93. package/dist/indexer/worker/worker.js +16 -3
  94. package/dist/indexer/worker/worker.js.map +1 -1
  95. package/dist/indexer/worker/worker.service.d.ts +10 -6
  96. package/dist/indexer/worker/worker.service.js +23 -10
  97. package/dist/indexer/worker/worker.service.js.map +1 -1
  98. package/dist/indexer/worker/worker.unfinalizedBlocks.service.d.ts +11 -0
  99. package/dist/indexer/worker/worker.unfinalizedBlocks.service.js +32 -0
  100. package/dist/indexer/worker/worker.unfinalizedBlocks.service.js.map +1 -0
  101. package/dist/init.js +2 -2
  102. package/dist/init.js.map +1 -1
  103. package/dist/main.js +6 -1
  104. package/dist/main.js.map +1 -1
  105. package/dist/meta/meta.module.js +8 -0
  106. package/dist/meta/meta.module.js.map +1 -1
  107. package/dist/meta/meta.service.d.ts +18 -3
  108. package/dist/meta/meta.service.js +89 -5
  109. package/dist/meta/meta.service.js.map +1 -1
  110. package/dist/subcommands/forceClean.service.d.ts +3 -1
  111. package/dist/subcommands/forceClean.service.js +30 -6
  112. package/dist/subcommands/forceClean.service.js.map +1 -1
  113. package/dist/subcommands/reindex.init.js +6 -1
  114. package/dist/subcommands/reindex.init.js.map +1 -1
  115. package/dist/subcommands/reindex.module.js +20 -1
  116. package/dist/subcommands/reindex.module.js.map +1 -1
  117. package/dist/subcommands/reindex.service.d.ts +7 -3
  118. package/dist/subcommands/reindex.service.js +44 -50
  119. package/dist/subcommands/reindex.service.js.map +1 -1
  120. package/dist/subcommands/testing.init.d.ts +1 -0
  121. package/dist/subcommands/testing.init.js +34 -0
  122. package/dist/subcommands/testing.init.js.map +1 -0
  123. package/dist/subcommands/testing.module.d.ts +4 -0
  124. package/dist/subcommands/testing.module.js +77 -0
  125. package/dist/subcommands/testing.module.js.map +1 -0
  126. package/dist/subcommands/testing.service.d.ts +9 -0
  127. package/dist/subcommands/testing.service.js +43 -0
  128. package/dist/subcommands/testing.service.js.map +1 -0
  129. package/dist/utils/project.d.ts +3 -0
  130. package/dist/utils/project.js +45 -1
  131. package/dist/utils/project.js.map +1 -1
  132. package/dist/utils/reindex.d.ts +6 -0
  133. package/dist/utils/reindex.js +48 -0
  134. package/dist/utils/reindex.js.map +1 -0
  135. package/dist/utils/string.js +10 -2
  136. package/dist/utils/string.js.map +1 -1
  137. package/dist/yargs.d.ts +97 -49
  138. package/dist/yargs.js +130 -69
  139. package/dist/yargs.js.map +1 -1
  140. package/package.json +13 -12
  141. package/dist/indexer/worker/block-dispatcher.service.d.ts +0 -69
  142. package/dist/indexer/worker/block-dispatcher.service.js +0 -356
  143. package/dist/indexer/worker/block-dispatcher.service.js.map +0 -1
@@ -26,19 +26,34 @@ const utils_ethereum_1 = require("../ethereum/utils.ethereum");
26
26
  const string_1 = require("../utils/string");
27
27
  const dictionary_service_1 = require("./dictionary.service");
28
28
  const dynamic_ds_service_1 = require("./dynamic-ds.service");
29
+ const unfinalizedBlocks_service_1 = require("./unfinalizedBlocks.service");
29
30
  const logger = (0, node_core_1.getLogger)('fetch');
30
31
  let BLOCK_TIME_VARIANCE = 5000;
31
32
  const DICTIONARY_MAX_QUERY_SIZE = 10000;
32
33
  const CHECK_MEMORY_INTERVAL = 60000;
33
34
  const MINIMUM_BATCH_SIZE = 5;
34
35
  const INTERVAL_PERCENT = 0.9;
35
- function eventFilterToQueryEntry(filter) {
36
+ const QUERY_ADDRESS_LIMIT = 50;
37
+ function eventFilterToQueryEntry(filter, dsOptions) {
36
38
  const conditions = [];
37
- if (filter.address) {
38
- conditions.push({
39
- field: 'address',
40
- value: filter.address.toLowerCase(),
41
- });
39
+ if (Array.isArray(dsOptions)) {
40
+ const addresses = dsOptions.map((option) => option.address).filter(Boolean);
41
+ if (addresses.length !== 0 && addresses.length <= QUERY_ADDRESS_LIMIT) {
42
+ conditions.push({
43
+ field: 'address',
44
+ value: addresses,
45
+ matcher: 'inInsensitive',
46
+ });
47
+ }
48
+ }
49
+ else {
50
+ if (dsOptions === null || dsOptions === void 0 ? void 0 : dsOptions.address) {
51
+ conditions.push({
52
+ field: 'address',
53
+ value: dsOptions.address.toLowerCase(),
54
+ // matcher: 'equals',
55
+ });
56
+ }
42
57
  }
43
58
  if (filter.topics) {
44
59
  for (let i = 0; i < Math.min(filter.topics.length, 4); i++) {
@@ -47,7 +62,11 @@ function eventFilterToQueryEntry(filter) {
47
62
  continue;
48
63
  }
49
64
  const field = `topics${i}`;
50
- conditions.push({ field, value: (0, string_1.eventToTopic)(topic) });
65
+ conditions.push({
66
+ field,
67
+ value: (0, string_1.eventToTopic)(topic),
68
+ matcher: 'equalTo',
69
+ });
51
70
  }
52
71
  }
53
72
  return {
@@ -73,6 +92,7 @@ function callFilterToQueryEntry(filter) {
73
92
  conditions.push({
74
93
  field: 'func',
75
94
  value: (0, string_1.functionToSighash)(filter.function),
95
+ matcher: 'equalTo',
76
96
  });
77
97
  }
78
98
  return {
@@ -81,16 +101,19 @@ function callFilterToQueryEntry(filter) {
81
101
  };
82
102
  }
83
103
  let FetchService = class FetchService {
84
- constructor(apiService, nodeConfig, project, blockDispatcher, dictionaryService, dynamicDsService, eventEmitter, schedulerRegistry) {
104
+ constructor(apiService, nodeConfig, project, blockDispatcher, dictionaryService, dynamicDsService, unfinalizedBlocksService, eventEmitter, schedulerRegistry) {
85
105
  this.apiService = apiService;
86
106
  this.nodeConfig = nodeConfig;
87
107
  this.project = project;
88
108
  this.blockDispatcher = blockDispatcher;
89
109
  this.dictionaryService = dictionaryService;
90
110
  this.dynamicDsService = dynamicDsService;
111
+ this.unfinalizedBlocksService = unfinalizedBlocksService;
91
112
  this.eventEmitter = eventEmitter;
92
113
  this.schedulerRegistry = schedulerRegistry;
93
114
  this.isShutdown = false;
115
+ this.dictionaryMetaValid = false;
116
+ this.bypassBlocks = [];
94
117
  this.batchSizeScale = 1;
95
118
  }
96
119
  onApplicationShutdown() {
@@ -103,41 +126,50 @@ let FetchService = class FetchService {
103
126
  this.templateDynamicDatasouces =
104
127
  await this.dynamicDsService.getDynamicDatasources();
105
128
  }
106
- // TODO: if custom ds doesn't support dictionary, use baseFilter, if yes, let
107
- getDictionaryQueryEntries() {
129
+ buildDictionaryQueryEntries(startBlock) {
130
+ var _a;
108
131
  const queryEntries = [];
109
- const dataSources = this.project.dataSources;
110
- for (const ds of dataSources.concat(this.templateDynamicDatasouces)) {
132
+ const groupdDynamicDs = Object.values((0, lodash_1.groupBy)(this.templateDynamicDatasouces, (ds) => ds.name)).map((grouped) => {
133
+ const options = grouped.map((ds) => ds.options);
134
+ const ref = grouped[0];
135
+ return Object.assign(Object.assign({}, ref), { groupedOptions: options });
136
+ });
137
+ // Only run the ds that is equal or less than startBlock
138
+ // sort array from lowest ds.startBlock to highest
139
+ const filteredDs = this.project.dataSources
140
+ .concat(groupdDynamicDs)
141
+ .filter((ds) => ds.startBlock <= startBlock)
142
+ .sort((a, b) => a.startBlock - b.startBlock);
143
+ for (const ds of filteredDs) {
111
144
  for (const handler of ds.mapping.handlers) {
112
- let filterList;
113
- filterList = [handler.filter];
114
- filterList = filterList.filter((f) => f);
115
- if (!filterList.length)
145
+ // No filters, cant use dictionary
146
+ if (!handler.filter)
116
147
  return [];
117
148
  switch (handler.kind) {
118
149
  case common_ethereum_1.EthereumHandlerKind.Block:
119
150
  return [];
120
151
  case common_ethereum_1.EthereumHandlerKind.Call: {
121
- for (const filter of filterList) {
122
- if (filter.from !== undefined ||
123
- filter.to !== undefined ||
124
- filter.function) {
125
- queryEntries.push(callFilterToQueryEntry(filter));
126
- }
127
- else {
128
- return [];
129
- }
152
+ const filter = handler.filter;
153
+ if (filter.from !== undefined ||
154
+ filter.to !== undefined ||
155
+ filter.function) {
156
+ queryEntries.push(callFilterToQueryEntry(filter));
157
+ }
158
+ else {
159
+ return [];
130
160
  }
131
161
  break;
132
162
  }
133
163
  case common_ethereum_1.EthereumHandlerKind.Event: {
134
- for (const filter of filterList) {
135
- if (filter.address || filter.topics) {
136
- queryEntries.push(eventFilterToQueryEntry(filter));
137
- }
138
- else {
139
- return [];
140
- }
164
+ const filter = handler.filter;
165
+ if (ds.groupedOptions) {
166
+ queryEntries.push(eventFilterToQueryEntry(filter, ds.groupedOptions));
167
+ }
168
+ else if (((_a = ds.options) === null || _a === void 0 ? void 0 : _a.address) || filter.topics) {
169
+ queryEntries.push(eventFilterToQueryEntry(filter, ds.options));
170
+ }
171
+ else {
172
+ return [];
141
173
  }
142
174
  break;
143
175
  }
@@ -148,13 +180,19 @@ let FetchService = class FetchService {
148
180
  return (0, lodash_1.uniqBy)(queryEntries, (item) => `${item.entity}|${JSON.stringify((0, lodash_1.sortBy)(item.conditions, (c) => c.field))}`);
149
181
  }
150
182
  updateDictionary() {
183
+ this.dictionaryService.buildDictionaryEntryMap(this.project.dataSources.concat(this.templateDynamicDatasouces), this.buildDictionaryQueryEntries.bind(this));
184
+ }
185
+ get useDictionary() {
151
186
  var _a;
152
- this.dictionaryQueryEntries = this.getDictionaryQueryEntries();
153
- this.useDictionary =
154
- !!((_a = this.dictionaryQueryEntries) === null || _a === void 0 ? void 0 : _a.length) &&
155
- !!this.project.network.dictionary;
187
+ return (!!this.project.network.dictionary &&
188
+ this.dictionaryMetaValid &&
189
+ !!this.dictionaryService.getDictionaryQueryEntries((_a = this.blockDispatcher.latestBufferedHeight) !== null && _a !== void 0 ? _a : Math.min(...this.project.dataSources.map((ds) => ds.startBlock))).length);
156
190
  }
157
191
  async init(startHeight) {
192
+ var _a;
193
+ if (((_a = this.project.network) === null || _a === void 0 ? void 0 : _a.bypassBlocks) !== undefined) {
194
+ this.bypassBlocks = (0, node_core_1.transformBypassBlocks)(this.project.network.bypassBlocks).filter((blk) => blk >= startHeight);
195
+ }
158
196
  if (this.api) {
159
197
  const CHAIN_INTERVAL = (0, utils_ethereum_1.calcInterval)(this.api) * INTERVAL_PERCENT;
160
198
  BLOCK_TIME_VARIANCE = Math.min(BLOCK_TIME_VARIANCE, CHAIN_INTERVAL);
@@ -162,14 +200,23 @@ let FetchService = class FetchService {
162
200
  }
163
201
  await this.syncDynamicDatascourcesFromMeta();
164
202
  this.updateDictionary();
165
- this.eventEmitter.emit(node_core_1.IndexerEvent.UsingDictionary, {
166
- value: Number(this.useDictionary),
167
- });
168
- await this.getFinalizedBlockHead();
169
- await this.getBestBlockHead();
203
+ // Call metadata here, other network should align with this
204
+ // For substrate, we might use the specVersion metadata in future if we have same error handling as in node-core
205
+ const metadata = await this.dictionaryService.getMetadata();
206
+ if (this.project.network.dictionary) {
207
+ this.evmChainId = await this.dictionaryService.getEvmChainId();
208
+ }
209
+ const dictionaryValid = this.dictionaryValidation(metadata);
210
+ await Promise.all([this.getFinalizedBlockHead(), this.getBestBlockHead()]);
170
211
  await this.blockDispatcher.init(this.resetForNewDs.bind(this));
171
212
  void this.startLoop(startHeight);
172
213
  }
214
+ getUseDictionary() {
215
+ return this.useDictionary;
216
+ }
217
+ getLatestFinalizedHeight() {
218
+ return this.latestFinalizedHeight;
219
+ }
173
220
  checkBatchScale() {
174
221
  if (this.nodeConfig['scale-batch-size']) {
175
222
  const scale = (0, node_core_1.checkMemoryUsage)(this.batchSizeScale, this.nodeConfig);
@@ -185,15 +232,22 @@ let FetchService = class FetchService {
185
232
  }
186
233
  try {
187
234
  const currentFinalizedHeight = await this.api.getFinalizedBlockHeight();
235
+ logger.debug(`finalized:${currentFinalizedHeight.toString()}`);
236
+ const finalizedHeader = await this.api.getBlockByHeightOrHash(currentFinalizedHeight);
188
237
  if (this.latestFinalizedHeight !== currentFinalizedHeight) {
189
238
  this.latestFinalizedHeight = currentFinalizedHeight;
190
- this.eventEmitter.emit(node_core_1.IndexerEvent.BlockTarget, {
191
- height: this.latestFinalizedHeight,
192
- });
239
+ this.unfinalizedBlocksService.registerFinalizedBlock(finalizedHeader);
240
+ if (!this.nodeConfig.unfinalizedBlocks) {
241
+ if (!this.nodeConfig.unfinalizedBlocks) {
242
+ this.eventEmitter.emit(node_core_1.IndexerEvent.BlockTarget, {
243
+ height: this.latestFinalizedHeight,
244
+ });
245
+ }
246
+ }
193
247
  }
194
248
  }
195
249
  catch (e) {
196
- logger.error(e, `Having a problem when get finalized block`);
250
+ logger.warn(e, `Having a problem when get finalized block`);
197
251
  }
198
252
  }
199
253
  async getBestBlockHead() {
@@ -202,16 +256,22 @@ let FetchService = class FetchService {
202
256
  return;
203
257
  }
204
258
  try {
205
- const currentBestHeight = await this.api.getLastHeight();
259
+ const currentBestHeight = await this.api.getBestBlockHeight();
260
+ logger.debug(`best:${currentBestHeight.toString()}`);
206
261
  if (this.latestBestHeight !== currentBestHeight) {
207
262
  this.latestBestHeight = currentBestHeight;
208
263
  this.eventEmitter.emit(node_core_1.IndexerEvent.BlockBest, {
209
264
  height: this.latestBestHeight,
210
265
  });
266
+ if (this.nodeConfig.unfinalizedBlocks) {
267
+ this.eventEmitter.emit(node_core_1.IndexerEvent.BlockTarget, {
268
+ height: this.latestBestHeight,
269
+ });
270
+ }
211
271
  }
212
272
  }
213
273
  catch (e) {
214
- logger.error(e, `Having a problem when get best block`);
274
+ logger.warn(e, `Having a problem when get best block`);
215
275
  }
216
276
  }
217
277
  async startLoop(initBlockHeight) {
@@ -256,19 +316,31 @@ let FetchService = class FetchService {
256
316
  ? this.blockDispatcher.latestBufferedHeight + 1
257
317
  : initBlockHeight;
258
318
  };
319
+ if (this.useDictionary &&
320
+ this.dictionaryService.startHeight > getStartBlockHeight()) {
321
+ logger.warn(`Dictionary start height ${this.dictionaryService.startHeight} is beyond indexing height ${getStartBlockHeight()}, skipping dictionary for now`);
322
+ }
259
323
  while (!this.isShutdown) {
260
324
  startBlockHeight = getStartBlockHeight();
261
- scaledBatchSize = Math.max(Math.round(this.batchSizeScale * this.nodeConfig.batchSize), Math.min(MINIMUM_BATCH_SIZE, this.nodeConfig.batchSize * 3));
325
+ scaledBatchSize = this.blockDispatcher.smartBatchSize;
326
+ if (scaledBatchSize === 0) {
327
+ await (0, node_core_1.waitForBatchSize)(this.blockDispatcher.minimumHeapLimit);
328
+ continue;
329
+ }
330
+ const latestHeight = this.nodeConfig.unfinalizedBlocks
331
+ ? this.latestBestHeight
332
+ : this.latestFinalizedHeight;
262
333
  if (this.blockDispatcher.freeSize < scaledBatchSize ||
263
- startBlockHeight > this.latestFinalizedHeight) {
334
+ startBlockHeight > latestHeight) {
264
335
  await (0, node_core_1.delay)(1);
265
336
  continue;
266
337
  }
267
- if (this.useDictionary) {
338
+ if (this.useDictionary &&
339
+ startBlockHeight >= this.dictionaryService.startHeight) {
268
340
  const queryEndBlock = startBlockHeight + DICTIONARY_MAX_QUERY_SIZE;
269
341
  const moduloBlocks = this.getModuloBlocks(startBlockHeight, queryEndBlock);
270
342
  try {
271
- const dictionary = await this.dictionaryService.getDictionary(startBlockHeight, queryEndBlock, scaledBatchSize, this.dictionaryQueryEntries);
343
+ const dictionary = await this.dictionaryService.scopedDictionaryEntries(startBlockHeight, queryEndBlock, scaledBatchSize);
272
344
  if (startBlockHeight !== getStartBlockHeight()) {
273
345
  logger.debug(`Queue was reset for new DS, discarding dictionary query result`);
274
346
  continue;
@@ -281,12 +353,13 @@ let FetchService = class FetchService {
281
353
  .sort((a, b) => a - b);
282
354
  if (batchBlocks.length === 0) {
283
355
  // There we're no blocks in this query range, we can set a new height we're up to
284
- this.blockDispatcher.latestBufferedHeight = Math.min(queryEndBlock - 1, dictionary._metadata.lastProcessedHeight);
356
+ await this.blockDispatcher.enqueueBlocks([], Math.min(queryEndBlock - 1, dictionary._metadata.lastProcessedHeight));
285
357
  }
286
358
  else {
287
359
  const maxBlockSize = Math.min(batchBlocks.length, this.blockDispatcher.freeSize);
288
- batchBlocks = batchBlocks.slice(0, maxBlockSize);
289
- this.blockDispatcher.enqueueBlocks(batchBlocks);
360
+ const enqueuingBlocks = batchBlocks.slice(0, maxBlockSize);
361
+ const cleanedBatchBlocks = this.filteredBlockBatch(enqueuingBlocks);
362
+ await this.blockDispatcher.enqueueBlocks(cleanedBatchBlocks, this.getLatestBufferHeight(cleanedBatchBlocks, enqueuingBlocks));
290
363
  }
291
364
  continue; // skip nextBlockRange() way
292
365
  }
@@ -298,37 +371,67 @@ let FetchService = class FetchService {
298
371
  }
299
372
  }
300
373
  const endHeight = this.nextEndBlockHeight(startBlockHeight, scaledBatchSize);
301
- if (this.getModulos().length === handlers.length) {
302
- this.blockDispatcher.enqueueBlocks(this.getEnqueuedModuloBlocks(startBlockHeight));
303
- }
304
- else {
305
- this.blockDispatcher.enqueueBlocks((0, lodash_1.range)(startBlockHeight, endHeight + 1));
306
- }
374
+ const enqueuingBlocks = handlers.length && this.getModulos().length === handlers.length
375
+ ? this.getEnqueuedModuloBlocks(startBlockHeight)
376
+ : (0, lodash_1.range)(startBlockHeight, endHeight + 1);
377
+ const cleanedBatchBlocks = this.filteredBlockBatch(enqueuingBlocks);
378
+ await this.blockDispatcher.enqueueBlocks(cleanedBatchBlocks, this.getLatestBufferHeight(cleanedBatchBlocks, enqueuingBlocks));
379
+ }
380
+ }
381
+ getLatestBufferHeight(cleanedBatchBlocks, rawBatchBlocks) {
382
+ return Math.max(...cleanedBatchBlocks, ...rawBatchBlocks);
383
+ }
384
+ filteredBlockBatch(currentBatchBlocks) {
385
+ if (!this.bypassBlocks.length || !currentBatchBlocks) {
386
+ return currentBatchBlocks;
387
+ }
388
+ const cleanedBatch = (0, node_core_1.cleanedBatchBlocks)(this.bypassBlocks, currentBatchBlocks);
389
+ const pollutedBlocks = this.bypassBlocks.filter((b) => b < Math.max(...currentBatchBlocks));
390
+ if (pollutedBlocks.length) {
391
+ logger.info(`Bypassing blocks: ${pollutedBlocks}`);
307
392
  }
393
+ this.bypassBlocks = (0, lodash_1.without)(this.bypassBlocks, ...pollutedBlocks);
394
+ return cleanedBatch;
308
395
  }
309
396
  nextEndBlockHeight(startBlockHeight, scaledBatchSize) {
310
397
  let endBlockHeight = startBlockHeight + scaledBatchSize - 1;
311
398
  if (endBlockHeight > this.latestFinalizedHeight) {
312
- endBlockHeight = this.latestFinalizedHeight;
399
+ if (this.nodeConfig.unfinalizedBlocks) {
400
+ if (endBlockHeight >= this.latestBestHeight) {
401
+ endBlockHeight = this.latestBestHeight;
402
+ }
403
+ }
404
+ else {
405
+ endBlockHeight = this.latestFinalizedHeight;
406
+ }
313
407
  }
314
408
  return endBlockHeight;
315
409
  }
316
- dictionaryValidation({ _metadata: metaData }, startBlockHeight) {
317
- if (metaData.genesisHash !== this.api.getGenesisHash()) {
318
- logger.error('The dictionary that you have specified does not match the chain you are indexing, it will be ignored. Please update your project manifest to reference the correct dictionary');
319
- this.useDictionary = false;
320
- this.eventEmitter.emit(node_core_1.IndexerEvent.UsingDictionary, {
321
- value: Number(this.useDictionary),
322
- });
323
- this.eventEmitter.emit(node_core_1.IndexerEvent.SkipDictionary);
324
- return false;
325
- }
326
- if (metaData.lastProcessedHeight < startBlockHeight) {
327
- logger.warn(`Dictionary indexed block is behind current indexing block height`);
328
- this.eventEmitter.emit(node_core_1.IndexerEvent.SkipDictionary);
410
+ dictionaryValidation(dictionary, startBlockHeight) {
411
+ const validate = () => {
412
+ if (dictionary !== undefined) {
413
+ const { _metadata: metaData } = dictionary;
414
+ if (metaData.genesisHash !== this.api.getGenesisHash() &&
415
+ this.evmChainId !== this.api.getChainId().toString()) {
416
+ logger.error('The dictionary that you have specified does not match the chain you are indexing, it will be ignored. Please update your project manifest to reference the correct dictionary');
417
+ return false;
418
+ }
419
+ if (startBlockHeight !== undefined &&
420
+ metaData.lastProcessedHeight < startBlockHeight) {
421
+ logger.warn(`Dictionary indexed block is behind current indexing block height`);
422
+ return false;
423
+ }
424
+ return true;
425
+ }
329
426
  return false;
330
- }
331
- return true;
427
+ };
428
+ const valid = validate();
429
+ this.dictionaryMetaValid = valid;
430
+ this.eventEmitter.emit(node_core_1.IndexerEvent.UsingDictionary, {
431
+ value: Number(this.useDictionary),
432
+ });
433
+ this.eventEmitter.emit(node_core_1.IndexerEvent.SkipDictionary);
434
+ return valid;
332
435
  }
333
436
  async resetForNewDs(blockHeight) {
334
437
  await this.syncDynamicDatascourcesFromMeta();
@@ -336,6 +439,11 @@ let FetchService = class FetchService {
336
439
  this.updateDictionary();
337
440
  this.blockDispatcher.flushQueue(blockHeight);
338
441
  }
442
+ async resetForIncorrectBestBlock(blockHeight) {
443
+ await this.syncDynamicDatascourcesFromMeta();
444
+ this.updateDictionary();
445
+ this.blockDispatcher.flushQueue(blockHeight);
446
+ }
339
447
  };
340
448
  __decorate([
341
449
  (0, schedule_1.Interval)(CHECK_MEMORY_INTERVAL),
@@ -344,24 +452,26 @@ __decorate([
344
452
  __metadata("design:returntype", void 0)
345
453
  ], FetchService.prototype, "checkBatchScale", null);
346
454
  __decorate([
347
- (0, schedule_1.Interval)(BLOCK_TIME_VARIANCE * 1000),
455
+ (0, schedule_1.Interval)(BLOCK_TIME_VARIANCE),
348
456
  __metadata("design:type", Function),
349
457
  __metadata("design:paramtypes", []),
350
458
  __metadata("design:returntype", Promise)
351
459
  ], FetchService.prototype, "getFinalizedBlockHead", null);
352
460
  __decorate([
353
- (0, schedule_1.Interval)(BLOCK_TIME_VARIANCE * 1000),
461
+ (0, schedule_1.Interval)(BLOCK_TIME_VARIANCE),
354
462
  __metadata("design:type", Function),
355
463
  __metadata("design:paramtypes", []),
356
464
  __metadata("design:returntype", Promise)
357
465
  ], FetchService.prototype, "getBestBlockHead", null);
358
466
  FetchService = __decorate([
359
467
  (0, common_1.Injectable)(),
468
+ __param(2, (0, common_1.Inject)('ISubqueryProject')),
360
469
  __param(3, (0, common_1.Inject)('IBlockDispatcher')),
361
470
  __metadata("design:paramtypes", [node_core_1.ApiService,
362
471
  node_core_1.NodeConfig,
363
472
  SubqueryProject_1.SubqueryProject, Object, dictionary_service_1.DictionaryService,
364
473
  dynamic_ds_service_1.DynamicDsService,
474
+ unfinalizedBlocks_service_1.UnfinalizedBlocksService,
365
475
  event_emitter_1.EventEmitter2,
366
476
  schedule_1.SchedulerRegistry])
367
477
  ], FetchService);
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.service.js","sourceRoot":"","sources":["../../src/indexer/fetch.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2022 OnFinality Limited authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { Interval, SchedulerRegistry } from '@nestjs/schedule';\nimport {\n isCustomDs,\n EthereumHandlerKind,\n SubqlHandlerFilter,\n} from '@subql/common-ethereum';\nimport {\n ApiService,\n Dictionary,\n checkMemoryUsage,\n delay,\n getLogger,\n IndexerEvent,\n NodeConfig,\n} from '@subql/node-core';\nimport {\n DictionaryQueryEntry,\n ApiWrapper,\n EthereumLogFilter,\n EthereumTransactionFilter,\n} from '@subql/types-ethereum';\nimport { range, sortBy, uniqBy } from 'lodash';\nimport { SubqlProjectDs, SubqueryProject } from '../configure/SubqueryProject';\nimport { calcInterval } from '../ethereum/utils.ethereum';\nimport { eventToTopic, functionToSighash } from '../utils/string';\nimport { DictionaryService } from './dictionary.service';\nimport { DynamicDsService } from './dynamic-ds.service';\nimport { IBlockDispatcher } from './worker/block-dispatcher.service';\n\nconst logger = getLogger('fetch');\nlet BLOCK_TIME_VARIANCE = 5000;\nconst DICTIONARY_MAX_QUERY_SIZE = 10000;\nconst CHECK_MEMORY_INTERVAL = 60000;\nconst MINIMUM_BATCH_SIZE = 5;\nconst INTERVAL_PERCENT = 0.9;\n\nfunction eventFilterToQueryEntry(\n filter: EthereumLogFilter,\n): DictionaryQueryEntry {\n const conditions = [];\n if (filter.address) {\n conditions.push({\n field: 'address',\n value: filter.address.toLowerCase(),\n });\n }\n if (filter.topics) {\n for (let i = 0; i < Math.min(filter.topics.length, 4); i++) {\n const topic = filter.topics[i];\n if (!topic) {\n continue;\n }\n const field = `topics${i}`;\n conditions.push({ field, value: eventToTopic(topic) });\n }\n }\n return {\n entity: 'evmLogs',\n conditions,\n };\n}\n\nfunction callFilterToQueryEntry(\n filter: EthereumTransactionFilter,\n): DictionaryQueryEntry {\n const conditions = [];\n if (filter.from) {\n conditions.push({\n field: 'from',\n value: filter.from.toLowerCase(),\n });\n }\n if (filter.to) {\n conditions.push({\n field: 'to',\n value: filter.to.toLowerCase(),\n });\n }\n if (filter.function) {\n conditions.push({\n field: 'func',\n value: functionToSighash(filter.function),\n });\n }\n return {\n entity: 'evmTransactions',\n conditions,\n };\n}\n\n@Injectable()\nexport class FetchService implements OnApplicationShutdown {\n private latestBestHeight: number;\n private latestFinalizedHeight: number;\n private isShutdown = false;\n private useDictionary: boolean;\n private dictionaryQueryEntries?: DictionaryQueryEntry[];\n private batchSizeScale: number;\n private templateDynamicDatasouces: SubqlProjectDs[];\n\n constructor(\n private apiService: ApiService,\n private nodeConfig: NodeConfig,\n private project: SubqueryProject,\n @Inject('IBlockDispatcher') private blockDispatcher: IBlockDispatcher,\n private dictionaryService: DictionaryService,\n private dynamicDsService: DynamicDsService,\n private eventEmitter: EventEmitter2,\n private schedulerRegistry: SchedulerRegistry,\n ) {\n this.batchSizeScale = 1;\n }\n\n onApplicationShutdown(): void {\n this.isShutdown = true;\n }\n\n get api(): ApiWrapper {\n return this.apiService.api;\n }\n\n async syncDynamicDatascourcesFromMeta(): Promise<void> {\n this.templateDynamicDatasouces =\n await this.dynamicDsService.getDynamicDatasources();\n }\n\n // TODO: if custom ds doesn't support dictionary, use baseFilter, if yes, let\n getDictionaryQueryEntries(): DictionaryQueryEntry[] {\n const queryEntries: DictionaryQueryEntry[] = [];\n\n const dataSources = this.project.dataSources;\n for (const ds of dataSources.concat(this.templateDynamicDatasouces)) {\n for (const handler of ds.mapping.handlers) {\n let filterList: SubqlHandlerFilter[];\n filterList = [handler.filter];\n filterList = filterList.filter((f) => f);\n if (!filterList.length) return [];\n switch (handler.kind) {\n case EthereumHandlerKind.Block:\n return [];\n case EthereumHandlerKind.Call: {\n for (const filter of filterList as EthereumTransactionFilter[]) {\n if (\n filter.from !== undefined ||\n filter.to !== undefined ||\n filter.function\n ) {\n queryEntries.push(callFilterToQueryEntry(filter));\n } else {\n return [];\n }\n }\n break;\n }\n case EthereumHandlerKind.Event: {\n for (const filter of filterList as EthereumLogFilter[]) {\n if (filter.address || filter.topics) {\n queryEntries.push(eventFilterToQueryEntry(filter));\n } else {\n return [];\n }\n }\n break;\n }\n default:\n }\n }\n }\n\n return uniqBy(\n queryEntries,\n (item) =>\n `${item.entity}|${JSON.stringify(\n sortBy(item.conditions, (c) => c.field),\n )}`,\n );\n }\n\n updateDictionary(): void {\n this.dictionaryQueryEntries = this.getDictionaryQueryEntries();\n this.useDictionary =\n !!this.dictionaryQueryEntries?.length &&\n !!this.project.network.dictionary;\n }\n\n async init(startHeight: number): Promise<void> {\n if (this.api) {\n const CHAIN_INTERVAL = calcInterval(this.api) * INTERVAL_PERCENT;\n\n BLOCK_TIME_VARIANCE = Math.min(BLOCK_TIME_VARIANCE, CHAIN_INTERVAL);\n\n this.schedulerRegistry.addInterval(\n 'getLatestBlockHead',\n setInterval(() => void this.getBestBlockHead(), BLOCK_TIME_VARIANCE),\n );\n }\n await this.syncDynamicDatascourcesFromMeta();\n this.updateDictionary();\n this.eventEmitter.emit(IndexerEvent.UsingDictionary, {\n value: Number(this.useDictionary),\n });\n await this.getFinalizedBlockHead();\n await this.getBestBlockHead();\n\n await this.blockDispatcher.init(this.resetForNewDs.bind(this));\n\n void this.startLoop(startHeight);\n }\n\n @Interval(CHECK_MEMORY_INTERVAL)\n checkBatchScale(): void {\n if (this.nodeConfig['scale-batch-size']) {\n const scale = checkMemoryUsage(this.batchSizeScale, this.nodeConfig);\n\n if (this.batchSizeScale !== scale) {\n this.batchSizeScale = scale;\n }\n }\n }\n\n @Interval(BLOCK_TIME_VARIANCE * 1000)\n async getFinalizedBlockHead(): Promise<void> {\n if (!this.api) {\n logger.debug(`Skip fetch finalized block until API is ready`);\n return;\n }\n try {\n const currentFinalizedHeight = await this.api.getFinalizedBlockHeight();\n if (this.latestFinalizedHeight !== currentFinalizedHeight) {\n this.latestFinalizedHeight = currentFinalizedHeight;\n this.eventEmitter.emit(IndexerEvent.BlockTarget, {\n height: this.latestFinalizedHeight,\n });\n }\n } catch (e) {\n logger.error(e, `Having a problem when get finalized block`);\n }\n }\n\n @Interval(BLOCK_TIME_VARIANCE * 1000)\n async getBestBlockHead(): Promise<void> {\n if (!this.api) {\n logger.debug(`Skip fetch best block until API is ready`);\n return;\n }\n try {\n const currentBestHeight = await this.api.getLastHeight();\n if (this.latestBestHeight !== currentBestHeight) {\n this.latestBestHeight = currentBestHeight;\n this.eventEmitter.emit(IndexerEvent.BlockBest, {\n height: this.latestBestHeight,\n });\n }\n } catch (e) {\n logger.error(e, `Having a problem when get best block`);\n }\n }\n\n async startLoop(initBlockHeight: number): Promise<void> {\n await this.fillNextBlockBuffer(initBlockHeight);\n }\n\n getModulos(): number[] {\n const modulos: number[] = [];\n for (const ds of this.project.dataSources) {\n if (isCustomDs(ds)) {\n continue;\n }\n for (const handler of ds.mapping.handlers) {\n if (\n handler.kind === EthereumHandlerKind.Block &&\n handler.filter &&\n handler.filter.modulo\n ) {\n modulos.push(handler.filter.modulo);\n }\n }\n }\n return modulos;\n }\n\n getModuloBlocks(startHeight: number, endHeight: number): number[] {\n const modulos = this.getModulos();\n const moduloBlocks: number[] = [];\n for (let i = startHeight; i < endHeight; i++) {\n if (modulos.find((m) => i % m === 0)) {\n moduloBlocks.push(i);\n }\n }\n return moduloBlocks;\n }\n\n getEnqueuedModuloBlocks(startBlockHeight: number): number[] {\n return this.getModuloBlocks(\n startBlockHeight,\n this.nodeConfig.batchSize * Math.max(...this.getModulos()) +\n startBlockHeight,\n ).slice(0, this.nodeConfig.batchSize);\n }\n\n async fillNextBlockBuffer(initBlockHeight: number): Promise<void> {\n let startBlockHeight: number;\n let scaledBatchSize: number;\n const handlers = [].concat(\n ...this.project.dataSources.map((ds) => ds.mapping.handlers),\n );\n\n const getStartBlockHeight = (): number => {\n return this.blockDispatcher.latestBufferedHeight\n ? this.blockDispatcher.latestBufferedHeight + 1\n : initBlockHeight;\n };\n\n while (!this.isShutdown) {\n startBlockHeight = getStartBlockHeight();\n\n scaledBatchSize = Math.max(\n Math.round(this.batchSizeScale * this.nodeConfig.batchSize),\n Math.min(MINIMUM_BATCH_SIZE, this.nodeConfig.batchSize * 3),\n );\n if (\n this.blockDispatcher.freeSize < scaledBatchSize ||\n startBlockHeight > this.latestFinalizedHeight\n ) {\n await delay(1);\n continue;\n }\n if (this.useDictionary) {\n const queryEndBlock = startBlockHeight + DICTIONARY_MAX_QUERY_SIZE;\n const moduloBlocks = this.getModuloBlocks(\n startBlockHeight,\n queryEndBlock,\n );\n try {\n const dictionary = await this.dictionaryService.getDictionary(\n startBlockHeight,\n queryEndBlock,\n scaledBatchSize,\n this.dictionaryQueryEntries,\n );\n\n if (startBlockHeight !== getStartBlockHeight()) {\n logger.debug(\n `Queue was reset for new DS, discarding dictionary query result`,\n );\n continue;\n }\n\n if (\n dictionary &&\n this.dictionaryValidation(dictionary, startBlockHeight)\n ) {\n let { batchBlocks } = dictionary;\n\n batchBlocks = batchBlocks\n .concat(moduloBlocks)\n .sort((a, b) => a - b);\n if (batchBlocks.length === 0) {\n // There we're no blocks in this query range, we can set a new height we're up to\n this.blockDispatcher.latestBufferedHeight = Math.min(\n queryEndBlock - 1,\n dictionary._metadata.lastProcessedHeight,\n );\n } else {\n const maxBlockSize = Math.min(\n batchBlocks.length,\n this.blockDispatcher.freeSize,\n );\n batchBlocks = batchBlocks.slice(0, maxBlockSize);\n this.blockDispatcher.enqueueBlocks(batchBlocks);\n }\n continue; // skip nextBlockRange() way\n }\n // else use this.nextBlockRange()\n } catch (e) {\n logger.debug(`Fetch dictionary stopped: ${e.message}`);\n this.eventEmitter.emit(IndexerEvent.SkipDictionary);\n }\n }\n const endHeight = this.nextEndBlockHeight(\n startBlockHeight,\n scaledBatchSize,\n );\n\n if (this.getModulos().length === handlers.length) {\n this.blockDispatcher.enqueueBlocks(\n this.getEnqueuedModuloBlocks(startBlockHeight),\n );\n } else {\n this.blockDispatcher.enqueueBlocks(\n range(startBlockHeight, endHeight + 1),\n );\n }\n }\n }\n\n private nextEndBlockHeight(\n startBlockHeight: number,\n scaledBatchSize: number,\n ): number {\n let endBlockHeight = startBlockHeight + scaledBatchSize - 1;\n\n if (endBlockHeight > this.latestFinalizedHeight) {\n endBlockHeight = this.latestFinalizedHeight;\n }\n return endBlockHeight;\n }\n\n private dictionaryValidation(\n { _metadata: metaData }: Dictionary,\n startBlockHeight: number,\n ): boolean {\n if (metaData.genesisHash !== this.api.getGenesisHash()) {\n logger.error(\n 'The dictionary that you have specified does not match the chain you are indexing, it will be ignored. Please update your project manifest to reference the correct dictionary',\n );\n this.useDictionary = false;\n this.eventEmitter.emit(IndexerEvent.UsingDictionary, {\n value: Number(this.useDictionary),\n });\n this.eventEmitter.emit(IndexerEvent.SkipDictionary);\n return false;\n }\n if (metaData.lastProcessedHeight < startBlockHeight) {\n logger.warn(\n `Dictionary indexed block is behind current indexing block height`,\n );\n this.eventEmitter.emit(IndexerEvent.SkipDictionary);\n return false;\n }\n return true;\n }\n\n async resetForNewDs(blockHeight: number): Promise<void> {\n await this.syncDynamicDatascourcesFromMeta();\n this.dynamicDsService.deleteTempDsRecords(blockHeight);\n this.updateDictionary();\n this.blockDispatcher.flushQueue(blockHeight);\n }\n}\n"]}
1
+ {"version":3,"file":"fetch.service.js","sourceRoot":"","sources":["../../src/indexer/fetch.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2022 OnFinality Limited authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { Interval, SchedulerRegistry } from '@nestjs/schedule';\n\nimport {\n isCustomDs,\n EthereumHandlerKind,\n EthereumLogFilter,\n SubqlEthereumProcessorOptions,\n EthereumTransactionFilter,\n} from '@subql/common-ethereum';\nimport {\n ApiService,\n cleanedBatchBlocks,\n checkMemoryUsage,\n delay,\n getLogger,\n IndexerEvent,\n NodeConfig,\n transformBypassBlocks,\n waitForBatchSize,\n} from '@subql/node-core';\nimport {\n ApiWrapper,\n DictionaryQueryCondition,\n DictionaryQueryEntry,\n} from '@subql/types-ethereum';\nimport { MetaData } from '@subql/utils';\nimport { groupBy, range, sortBy, uniqBy, without } from 'lodash';\nimport { SubqlProjectDs, SubqueryProject } from '../configure/SubqueryProject';\nimport { calcInterval } from '../ethereum/utils.ethereum';\nimport { eventToTopic, functionToSighash } from '../utils/string';\nimport { IEthereumBlockDispatcher } from './blockDispatcher';\nimport { DictionaryService } from './dictionary.service';\nimport { DynamicDsService } from './dynamic-ds.service';\nimport { UnfinalizedBlocksService } from './unfinalizedBlocks.service';\n\nconst logger = getLogger('fetch');\nlet BLOCK_TIME_VARIANCE = 5000;\nconst DICTIONARY_MAX_QUERY_SIZE = 10000;\nconst CHECK_MEMORY_INTERVAL = 60000;\nconst MINIMUM_BATCH_SIZE = 5;\nconst INTERVAL_PERCENT = 0.9;\nconst QUERY_ADDRESS_LIMIT = 50;\n\nfunction eventFilterToQueryEntry(\n filter: EthereumLogFilter,\n dsOptions: SubqlEthereumProcessorOptions | SubqlEthereumProcessorOptions[],\n): DictionaryQueryEntry {\n const conditions: DictionaryQueryCondition[] = [];\n\n if (Array.isArray(dsOptions)) {\n const addresses = dsOptions.map((option) => option.address).filter(Boolean);\n\n if (addresses.length !== 0 && addresses.length <= QUERY_ADDRESS_LIMIT) {\n conditions.push({\n field: 'address',\n value: addresses,\n matcher: 'inInsensitive',\n });\n }\n } else {\n if (dsOptions?.address) {\n conditions.push({\n field: 'address',\n value: dsOptions.address.toLowerCase(),\n // matcher: 'equals',\n });\n }\n }\n if (filter.topics) {\n for (let i = 0; i < Math.min(filter.topics.length, 4); i++) {\n const topic = filter.topics[i];\n if (!topic) {\n continue;\n }\n const field = `topics${i}`;\n conditions.push({\n field,\n value: eventToTopic(topic),\n matcher: 'equalTo',\n });\n }\n }\n return {\n entity: 'evmLogs',\n conditions,\n };\n}\n\nfunction callFilterToQueryEntry(\n filter: EthereumTransactionFilter,\n): DictionaryQueryEntry {\n const conditions: DictionaryQueryCondition[] = [];\n if (filter.from) {\n conditions.push({\n field: 'from',\n value: filter.from.toLowerCase(),\n });\n }\n if (filter.to) {\n conditions.push({\n field: 'to',\n value: filter.to.toLowerCase(),\n });\n }\n if (filter.function) {\n conditions.push({\n field: 'func',\n value: functionToSighash(filter.function),\n matcher: 'equalTo',\n });\n }\n return {\n entity: 'evmTransactions',\n conditions,\n };\n}\n\n@Injectable()\nexport class FetchService implements OnApplicationShutdown {\n private latestBestHeight: number;\n private latestFinalizedHeight: number;\n private isShutdown = false;\n private batchSizeScale: number;\n private templateDynamicDatasouces: SubqlProjectDs[];\n private dictionaryMetaValid = false;\n private evmChainId: string;\n private bypassBlocks: number[] = [];\n\n constructor(\n private apiService: ApiService,\n private nodeConfig: NodeConfig,\n @Inject('ISubqueryProject') private project: SubqueryProject,\n @Inject('IBlockDispatcher')\n private blockDispatcher: IEthereumBlockDispatcher,\n private dictionaryService: DictionaryService,\n private dynamicDsService: DynamicDsService,\n private unfinalizedBlocksService: UnfinalizedBlocksService,\n private eventEmitter: EventEmitter2,\n private schedulerRegistry: SchedulerRegistry,\n ) {\n this.batchSizeScale = 1;\n }\n\n onApplicationShutdown(): void {\n this.isShutdown = true;\n }\n\n get api(): ApiWrapper {\n return this.apiService.api;\n }\n\n async syncDynamicDatascourcesFromMeta(): Promise<void> {\n this.templateDynamicDatasouces =\n await this.dynamicDsService.getDynamicDatasources();\n }\n\n buildDictionaryQueryEntries(startBlock: number): DictionaryQueryEntry[] {\n const queryEntries: DictionaryQueryEntry[] = [];\n\n type GroupedSubqlProjectDs = SubqlProjectDs & {\n groupedOptions?: SubqlEthereumProcessorOptions[];\n };\n\n const groupdDynamicDs: GroupedSubqlProjectDs[] = Object.values(\n groupBy(this.templateDynamicDatasouces, (ds) => ds.name),\n ).map((grouped: SubqlProjectDs[]) => {\n const options = grouped.map((ds) => ds.options);\n const ref = grouped[0];\n\n return {\n ...ref,\n groupedOptions: options,\n };\n });\n\n // Only run the ds that is equal or less than startBlock\n // sort array from lowest ds.startBlock to highest\n const filteredDs: GroupedSubqlProjectDs[] = this.project.dataSources\n .concat(groupdDynamicDs)\n .filter((ds) => ds.startBlock <= startBlock)\n .sort((a, b) => a.startBlock - b.startBlock);\n\n for (const ds of filteredDs) {\n for (const handler of ds.mapping.handlers) {\n // No filters, cant use dictionary\n if (!handler.filter) return [];\n\n switch (handler.kind) {\n case EthereumHandlerKind.Block:\n return [];\n case EthereumHandlerKind.Call: {\n const filter = handler.filter as EthereumTransactionFilter;\n if (\n filter.from !== undefined ||\n filter.to !== undefined ||\n filter.function\n ) {\n queryEntries.push(callFilterToQueryEntry(filter));\n } else {\n return [];\n }\n break;\n }\n case EthereumHandlerKind.Event: {\n const filter = handler.filter as EthereumLogFilter;\n if (ds.groupedOptions) {\n queryEntries.push(\n eventFilterToQueryEntry(filter, ds.groupedOptions),\n );\n } else if (ds.options?.address || filter.topics) {\n queryEntries.push(eventFilterToQueryEntry(filter, ds.options));\n } else {\n return [];\n }\n break;\n }\n default:\n }\n }\n }\n\n return uniqBy(\n queryEntries,\n (item) =>\n `${item.entity}|${JSON.stringify(\n sortBy(item.conditions, (c) => c.field),\n )}`,\n );\n }\n\n updateDictionary(): void {\n this.dictionaryService.buildDictionaryEntryMap<SubqlProjectDs>(\n this.project.dataSources.concat(this.templateDynamicDatasouces),\n this.buildDictionaryQueryEntries.bind(this),\n );\n }\n\n private get useDictionary(): boolean {\n return (\n !!this.project.network.dictionary &&\n this.dictionaryMetaValid &&\n !!this.dictionaryService.getDictionaryQueryEntries(\n this.blockDispatcher.latestBufferedHeight ??\n Math.min(...this.project.dataSources.map((ds) => ds.startBlock)),\n ).length\n );\n }\n\n async init(startHeight: number): Promise<void> {\n if (this.project.network?.bypassBlocks !== undefined) {\n this.bypassBlocks = transformBypassBlocks(\n this.project.network.bypassBlocks,\n ).filter((blk) => blk >= startHeight);\n }\n if (this.api) {\n const CHAIN_INTERVAL = calcInterval(this.api) * INTERVAL_PERCENT;\n\n BLOCK_TIME_VARIANCE = Math.min(BLOCK_TIME_VARIANCE, CHAIN_INTERVAL);\n\n this.schedulerRegistry.addInterval(\n 'getLatestBlockHead',\n setInterval(() => void this.getBestBlockHead(), BLOCK_TIME_VARIANCE),\n );\n }\n await this.syncDynamicDatascourcesFromMeta();\n\n this.updateDictionary();\n // Call metadata here, other network should align with this\n // For substrate, we might use the specVersion metadata in future if we have same error handling as in node-core\n const metadata = await this.dictionaryService.getMetadata();\n if (this.project.network.dictionary) {\n this.evmChainId = await this.dictionaryService.getEvmChainId();\n }\n const dictionaryValid = this.dictionaryValidation(metadata);\n\n await Promise.all([this.getFinalizedBlockHead(), this.getBestBlockHead()]);\n\n await this.blockDispatcher.init(this.resetForNewDs.bind(this));\n void this.startLoop(startHeight);\n }\n\n getUseDictionary(): boolean {\n return this.useDictionary;\n }\n\n getLatestFinalizedHeight(): number {\n return this.latestFinalizedHeight;\n }\n\n @Interval(CHECK_MEMORY_INTERVAL)\n checkBatchScale(): void {\n if (this.nodeConfig['scale-batch-size']) {\n const scale = checkMemoryUsage(this.batchSizeScale, this.nodeConfig);\n\n if (this.batchSizeScale !== scale) {\n this.batchSizeScale = scale;\n }\n }\n }\n\n @Interval(BLOCK_TIME_VARIANCE)\n async getFinalizedBlockHead(): Promise<void> {\n if (!this.api) {\n logger.debug(`Skip fetch finalized block until API is ready`);\n return;\n }\n try {\n const currentFinalizedHeight = await this.api.getFinalizedBlockHeight();\n logger.debug(`finalized:${currentFinalizedHeight.toString()}`);\n const finalizedHeader = await this.api.getBlockByHeightOrHash(\n currentFinalizedHeight,\n );\n if (this.latestFinalizedHeight !== currentFinalizedHeight) {\n this.latestFinalizedHeight = currentFinalizedHeight;\n this.unfinalizedBlocksService.registerFinalizedBlock(finalizedHeader);\n if (!this.nodeConfig.unfinalizedBlocks) {\n if (!this.nodeConfig.unfinalizedBlocks) {\n this.eventEmitter.emit(IndexerEvent.BlockTarget, {\n height: this.latestFinalizedHeight,\n });\n }\n }\n }\n } catch (e) {\n logger.warn(e, `Having a problem when get finalized block`);\n }\n }\n\n @Interval(BLOCK_TIME_VARIANCE)\n async getBestBlockHead(): Promise<void> {\n if (!this.api) {\n logger.debug(`Skip fetch best block until API is ready`);\n return;\n }\n try {\n const currentBestHeight = await this.api.getBestBlockHeight();\n logger.debug(`best:${currentBestHeight.toString()}`);\n if (this.latestBestHeight !== currentBestHeight) {\n this.latestBestHeight = currentBestHeight;\n this.eventEmitter.emit(IndexerEvent.BlockBest, {\n height: this.latestBestHeight,\n });\n\n if (this.nodeConfig.unfinalizedBlocks) {\n this.eventEmitter.emit(IndexerEvent.BlockTarget, {\n height: this.latestBestHeight,\n });\n }\n }\n } catch (e) {\n logger.warn(e, `Having a problem when get best block`);\n }\n }\n private async startLoop(initBlockHeight: number): Promise<void> {\n await this.fillNextBlockBuffer(initBlockHeight);\n }\n\n getModulos(): number[] {\n const modulos: number[] = [];\n for (const ds of this.project.dataSources) {\n if (isCustomDs(ds)) {\n continue;\n }\n for (const handler of ds.mapping.handlers) {\n if (\n handler.kind === EthereumHandlerKind.Block &&\n handler.filter &&\n handler.filter.modulo\n ) {\n modulos.push(handler.filter.modulo);\n }\n }\n }\n return modulos;\n }\n\n getModuloBlocks(startHeight: number, endHeight: number): number[] {\n const modulos = this.getModulos();\n const moduloBlocks: number[] = [];\n for (let i = startHeight; i < endHeight; i++) {\n if (modulos.find((m) => i % m === 0)) {\n moduloBlocks.push(i);\n }\n }\n return moduloBlocks;\n }\n\n getEnqueuedModuloBlocks(startBlockHeight: number): number[] {\n return this.getModuloBlocks(\n startBlockHeight,\n this.nodeConfig.batchSize * Math.max(...this.getModulos()) +\n startBlockHeight,\n ).slice(0, this.nodeConfig.batchSize);\n }\n\n async fillNextBlockBuffer(initBlockHeight: number): Promise<void> {\n let startBlockHeight: number;\n let scaledBatchSize: number;\n const handlers = [].concat(\n ...this.project.dataSources.map((ds) => ds.mapping.handlers),\n );\n\n const getStartBlockHeight = (): number => {\n return this.blockDispatcher.latestBufferedHeight\n ? this.blockDispatcher.latestBufferedHeight + 1\n : initBlockHeight;\n };\n\n if (\n this.useDictionary &&\n this.dictionaryService.startHeight > getStartBlockHeight()\n ) {\n logger.warn(\n `Dictionary start height ${\n this.dictionaryService.startHeight\n } is beyond indexing height ${getStartBlockHeight()}, skipping dictionary for now`,\n );\n }\n\n while (!this.isShutdown) {\n startBlockHeight = getStartBlockHeight();\n\n scaledBatchSize = this.blockDispatcher.smartBatchSize;\n\n if (scaledBatchSize === 0) {\n await waitForBatchSize(this.blockDispatcher.minimumHeapLimit);\n continue;\n }\n\n const latestHeight = this.nodeConfig.unfinalizedBlocks\n ? this.latestBestHeight\n : this.latestFinalizedHeight;\n\n if (\n this.blockDispatcher.freeSize < scaledBatchSize ||\n startBlockHeight > latestHeight\n ) {\n await delay(1);\n continue;\n }\n\n if (\n this.useDictionary &&\n startBlockHeight >= this.dictionaryService.startHeight\n ) {\n const queryEndBlock = startBlockHeight + DICTIONARY_MAX_QUERY_SIZE;\n const moduloBlocks = this.getModuloBlocks(\n startBlockHeight,\n queryEndBlock,\n );\n\n try {\n const dictionary =\n await this.dictionaryService.scopedDictionaryEntries(\n startBlockHeight,\n queryEndBlock,\n scaledBatchSize,\n );\n\n if (startBlockHeight !== getStartBlockHeight()) {\n logger.debug(\n `Queue was reset for new DS, discarding dictionary query result`,\n );\n continue;\n }\n\n if (\n dictionary &&\n this.dictionaryValidation(dictionary, startBlockHeight)\n ) {\n let { batchBlocks } = dictionary;\n\n batchBlocks = batchBlocks\n .concat(moduloBlocks)\n .sort((a, b) => a - b);\n if (batchBlocks.length === 0) {\n // There we're no blocks in this query range, we can set a new height we're up to\n await this.blockDispatcher.enqueueBlocks(\n [],\n Math.min(\n queryEndBlock - 1,\n dictionary._metadata.lastProcessedHeight,\n ),\n );\n } else {\n const maxBlockSize = Math.min(\n batchBlocks.length,\n this.blockDispatcher.freeSize,\n );\n const enqueuingBlocks = batchBlocks.slice(0, maxBlockSize);\n const cleanedBatchBlocks =\n this.filteredBlockBatch(enqueuingBlocks);\n await this.blockDispatcher.enqueueBlocks(\n cleanedBatchBlocks,\n this.getLatestBufferHeight(cleanedBatchBlocks, enqueuingBlocks),\n );\n }\n continue; // skip nextBlockRange() way\n }\n // else use this.nextBlockRange()\n } catch (e) {\n logger.debug(`Fetch dictionary stopped: ${e.message}`);\n this.eventEmitter.emit(IndexerEvent.SkipDictionary);\n }\n }\n\n const endHeight = this.nextEndBlockHeight(\n startBlockHeight,\n scaledBatchSize,\n );\n\n const enqueuingBlocks =\n handlers.length && this.getModulos().length === handlers.length\n ? this.getEnqueuedModuloBlocks(startBlockHeight)\n : range(startBlockHeight, endHeight + 1);\n\n const cleanedBatchBlocks = this.filteredBlockBatch(enqueuingBlocks);\n await this.blockDispatcher.enqueueBlocks(\n cleanedBatchBlocks,\n this.getLatestBufferHeight(cleanedBatchBlocks, enqueuingBlocks),\n );\n }\n }\n\n private getLatestBufferHeight(\n cleanedBatchBlocks: number[],\n rawBatchBlocks: number[],\n ): number {\n return Math.max(...cleanedBatchBlocks, ...rawBatchBlocks);\n }\n private filteredBlockBatch(currentBatchBlocks: number[]): number[] {\n if (!this.bypassBlocks.length || !currentBatchBlocks) {\n return currentBatchBlocks;\n }\n\n const cleanedBatch = cleanedBatchBlocks(\n this.bypassBlocks,\n currentBatchBlocks,\n );\n\n const pollutedBlocks = this.bypassBlocks.filter(\n (b) => b < Math.max(...currentBatchBlocks),\n );\n if (pollutedBlocks.length) {\n logger.info(`Bypassing blocks: ${pollutedBlocks}`);\n }\n this.bypassBlocks = without(this.bypassBlocks, ...pollutedBlocks);\n return cleanedBatch;\n }\n\n private nextEndBlockHeight(\n startBlockHeight: number,\n scaledBatchSize: number,\n ): number {\n let endBlockHeight = startBlockHeight + scaledBatchSize - 1;\n\n if (endBlockHeight > this.latestFinalizedHeight) {\n if (this.nodeConfig.unfinalizedBlocks) {\n if (endBlockHeight >= this.latestBestHeight) {\n endBlockHeight = this.latestBestHeight;\n }\n } else {\n endBlockHeight = this.latestFinalizedHeight;\n }\n }\n return endBlockHeight;\n }\n\n private dictionaryValidation(\n dictionary: { _metadata: MetaData },\n startBlockHeight?: number,\n ): boolean {\n const validate = (): boolean => {\n if (dictionary !== undefined) {\n const { _metadata: metaData } = dictionary;\n\n if (\n metaData.genesisHash !== this.api.getGenesisHash() &&\n this.evmChainId !== this.api.getChainId().toString()\n ) {\n logger.error(\n 'The dictionary that you have specified does not match the chain you are indexing, it will be ignored. Please update your project manifest to reference the correct dictionary',\n );\n return false;\n }\n\n if (\n startBlockHeight !== undefined &&\n metaData.lastProcessedHeight < startBlockHeight\n ) {\n logger.warn(\n `Dictionary indexed block is behind current indexing block height`,\n );\n return false;\n }\n return true;\n }\n return false;\n };\n\n const valid = validate();\n\n this.dictionaryMetaValid = valid;\n this.eventEmitter.emit(IndexerEvent.UsingDictionary, {\n value: Number(this.useDictionary),\n });\n this.eventEmitter.emit(IndexerEvent.SkipDictionary);\n\n return valid;\n }\n\n async resetForNewDs(blockHeight: number): Promise<void> {\n await this.syncDynamicDatascourcesFromMeta();\n this.dynamicDsService.deleteTempDsRecords(blockHeight);\n this.updateDictionary();\n this.blockDispatcher.flushQueue(blockHeight);\n }\n async resetForIncorrectBestBlock(blockHeight: number): Promise<void> {\n await this.syncDynamicDatascourcesFromMeta();\n this.updateDictionary();\n this.blockDispatcher.flushQueue(blockHeight);\n }\n}\n"]}
@@ -1,34 +1,28 @@
1
- import { ApiService, StoreService, PoiService, NodeConfig } from '@subql/node-core';
1
+ import { NodeConfig, ProcessBlockResponse, ApiService, IIndexerManager } from '@subql/node-core';
2
2
  import { EthereumBlockWrapper } from '@subql/types-ethereum';
3
- import { Sequelize } from 'sequelize';
4
- import { SubqueryProject } from '../configure/SubqueryProject';
3
+ import { SubqlProjectDs } from '../configure/SubqueryProject';
5
4
  import { DsProcessorService } from './ds-processor.service';
6
5
  import { DynamicDsService } from './dynamic-ds.service';
7
6
  import { ProjectService } from './project.service';
8
7
  import { SandboxService } from './sandbox.service';
9
- export declare class IndexerManager {
10
- private storeService;
8
+ import { UnfinalizedBlocksService } from './unfinalizedBlocks.service';
9
+ export declare class IndexerManager implements IIndexerManager<EthereumBlockWrapper, SubqlProjectDs> {
11
10
  private apiService;
12
- private poiService;
13
- private sequelize;
14
- private project;
15
11
  private nodeConfig;
16
12
  private sandboxService;
17
- private dynamicDsService;
18
13
  private dsProcessorService;
14
+ private dynamicDsService;
15
+ private unfinalizedBlocksService;
19
16
  private projectService;
20
- private api;
21
- private filteredDataSources;
22
- constructor(storeService: StoreService, apiService: ApiService, poiService: PoiService, sequelize: Sequelize, project: SubqueryProject, nodeConfig: NodeConfig, sandboxService: SandboxService, dynamicDsService: DynamicDsService, dsProcessorService: DsProcessorService, projectService: ProjectService);
23
- indexBlock(blockContent: EthereumBlockWrapper): Promise<{
24
- dynamicDsCreated: boolean;
25
- operationHash: Uint8Array;
26
- }>;
17
+ constructor(apiService: ApiService, nodeConfig: NodeConfig, sandboxService: SandboxService, dsProcessorService: DsProcessorService, dynamicDsService: DynamicDsService, unfinalizedBlocksService: UnfinalizedBlocksService, projectService: ProjectService);
18
+ indexBlock(blockContent: EthereumBlockWrapper, dataSources: SubqlProjectDs[]): Promise<ProcessBlockResponse>;
27
19
  start(): Promise<void>;
20
+ private processUnfinalizedBlocks;
28
21
  private filterDataSources;
22
+ private assertDataSources;
29
23
  private indexBlockData;
30
24
  private indexBlockContent;
31
- private indexExtrinsic;
25
+ private indexTransaction;
32
26
  private indexEvent;
33
27
  private indexData;
34
28
  private filterCustomDsHandlers;