@subql/node-ethereum 0.4.1-12 → 0.4.1-12-storeCache-0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ethereum/api.ethereum.d.ts +4 -1
  3. package/dist/ethereum/api.ethereum.js +30 -4
  4. package/dist/ethereum/api.ethereum.js.map +1 -1
  5. package/dist/ethereum/api.service.ethereum.js +1 -1
  6. package/dist/ethereum/api.service.ethereum.js.map +1 -1
  7. package/dist/ethereum/ethers/json-rpc-batch-provider.d.ts +21 -0
  8. package/dist/ethereum/ethers/json-rpc-batch-provider.js +102 -0
  9. package/dist/ethereum/ethers/json-rpc-batch-provider.js.map +1 -0
  10. package/dist/ethereum/ethers/json-rpc-provider.d.ts +7 -0
  11. package/dist/ethereum/ethers/json-rpc-provider.js +68 -0
  12. package/dist/ethereum/ethers/json-rpc-provider.js.map +1 -0
  13. package/dist/ethereum/ethers/web/_version.d.ts +1 -0
  14. package/dist/ethereum/ethers/web/_version.js +6 -0
  15. package/dist/ethereum/ethers/web/_version.js.map +1 -0
  16. package/dist/ethereum/ethers/web/geturl.d.ts +3 -0
  17. package/dist/ethereum/ethers/web/geturl.js +116 -0
  18. package/dist/ethereum/ethers/web/geturl.js.map +1 -0
  19. package/dist/ethereum/ethers/web/index.d.ts +49 -0
  20. package/dist/ethereum/ethers/web/index.js +433 -0
  21. package/dist/ethereum/ethers/web/index.js.map +1 -0
  22. package/dist/ethereum/ethers/web/types.d.ts +26 -0
  23. package/dist/ethereum/ethers/web/types.js +4 -0
  24. package/dist/ethereum/ethers/web/types.js.map +1 -0
  25. package/dist/indexer/blockDispatcher/block-dispatcher.service.js +4 -0
  26. package/dist/indexer/blockDispatcher/block-dispatcher.service.js.map +1 -1
  27. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js +5 -0
  28. package/dist/indexer/blockDispatcher/worker-block-dispatcher.service.js.map +1 -1
  29. package/dist/indexer/indexer.manager.d.ts +1 -1
  30. package/dist/indexer/indexer.manager.js +10 -8
  31. package/dist/indexer/indexer.manager.js.map +1 -1
  32. package/dist/meta/meta.service.d.ts +17 -2
  33. package/dist/meta/meta.service.js +86 -2
  34. package/dist/meta/meta.service.js.map +1 -1
  35. package/package.json +6 -6
@@ -0,0 +1,49 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import http from 'http';
4
+ import https from 'https';
5
+ export declare type ConnectionInfo = {
6
+ url: string;
7
+ headers?: {
8
+ [key: string]: string | number;
9
+ };
10
+ user?: string;
11
+ password?: string;
12
+ allowInsecureAuthentication?: boolean;
13
+ allowGzip?: boolean;
14
+ throttleLimit?: number;
15
+ throttleSlotInterval?: number;
16
+ throttleCallback?: (attempt: number, url: string) => Promise<boolean>;
17
+ skipFetchSetup?: boolean;
18
+ fetchOptions?: Record<string, string>;
19
+ errorPassThrough?: boolean;
20
+ timeout?: number;
21
+ agents?: {
22
+ http?: http.Agent;
23
+ https?: https.Agent;
24
+ };
25
+ };
26
+ export interface OnceBlockable {
27
+ once(eventName: 'block', handler: () => void): void;
28
+ }
29
+ export interface OncePollable {
30
+ once(eventName: 'poll', handler: () => void): void;
31
+ }
32
+ export declare type PollOptions = {
33
+ timeout?: number;
34
+ floor?: number;
35
+ ceiling?: number;
36
+ interval?: number;
37
+ retryLimit?: number;
38
+ onceBlock?: OnceBlockable;
39
+ oncePoll?: OncePollable;
40
+ };
41
+ export declare type FetchJsonResponse = {
42
+ statusCode: number;
43
+ headers: {
44
+ [header: string]: string;
45
+ };
46
+ };
47
+ export declare function _fetchData<T = Uint8Array>(connection: string | ConnectionInfo, body?: Uint8Array, processFunc?: (value: Uint8Array, response: FetchJsonResponse) => T): Promise<T>;
48
+ export declare function fetchJson(connection: string | ConnectionInfo, json?: string, processFunc?: (value: any, response: FetchJsonResponse) => any): Promise<any>;
49
+ export declare function poll<T>(func: () => Promise<T>, options?: PollOptions): Promise<T>;
@@ -0,0 +1,433 @@
1
+ /* eslint-disable */
2
+ 'use strict';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.poll = exports.fetchJson = exports._fetchData = void 0;
5
+ const base64_1 = require("@ethersproject/base64");
6
+ const bytes_1 = require("@ethersproject/bytes");
7
+ const properties_1 = require("@ethersproject/properties");
8
+ const strings_1 = require("@ethersproject/strings");
9
+ const logger_1 = require("@ethersproject/logger");
10
+ const _version_1 = require("./_version");
11
+ const logger = new logger_1.Logger(_version_1.version);
12
+ const geturl_1 = require("./geturl");
13
+ function staller(duration) {
14
+ return new Promise((resolve) => {
15
+ setTimeout(resolve, duration);
16
+ });
17
+ }
18
+ function bodyify(value, type) {
19
+ if (value == null) {
20
+ return null;
21
+ }
22
+ if (typeof value === 'string') {
23
+ return value;
24
+ }
25
+ if ((0, bytes_1.isBytesLike)(value)) {
26
+ if (type &&
27
+ (type.split('/')[0] === 'text' ||
28
+ type.split(';')[0].trim() === 'application/json')) {
29
+ try {
30
+ return (0, strings_1.toUtf8String)(value);
31
+ }
32
+ catch (error) { }
33
+ }
34
+ return (0, bytes_1.hexlify)(value);
35
+ }
36
+ return value;
37
+ }
38
+ function unpercent(value) {
39
+ return (0, strings_1.toUtf8Bytes)(value.replace(/%([0-9a-f][0-9a-f])/gi, (all, code) => {
40
+ return String.fromCharCode(parseInt(code, 16));
41
+ }));
42
+ }
43
+ // This API is still a work in progress; the future changes will likely be:
44
+ // - ConnectionInfo => FetchDataRequest<T = any>
45
+ // - FetchDataRequest.body? = string | Uint8Array | { contentType: string, data: string | Uint8Array }
46
+ // - If string => text/plain, Uint8Array => application/octet-stream (if content-type unspecified)
47
+ // - FetchDataRequest.processFunc = (body: Uint8Array, response: FetchDataResponse) => T
48
+ // For this reason, it should be considered internal until the API is finalized
49
+ function _fetchData(connection, body, processFunc) {
50
+ // How many times to retry in the event of a throttle
51
+ const attemptLimit = typeof connection === 'object' && connection.throttleLimit != null
52
+ ? connection.throttleLimit
53
+ : 12;
54
+ logger.assertArgument(attemptLimit > 0 && attemptLimit % 1 === 0, 'invalid connection throttle limit', 'connection.throttleLimit', attemptLimit);
55
+ const throttleCallback = typeof connection === 'object' ? connection.throttleCallback : null;
56
+ const throttleSlotInterval = typeof connection === 'object' &&
57
+ typeof connection.throttleSlotInterval === 'number'
58
+ ? connection.throttleSlotInterval
59
+ : 100;
60
+ logger.assertArgument(throttleSlotInterval > 0 && throttleSlotInterval % 1 === 0, 'invalid connection throttle slot interval', 'connection.throttleSlotInterval', throttleSlotInterval);
61
+ const errorPassThrough = typeof connection === 'object' ? !!connection.errorPassThrough : false;
62
+ const headers = {};
63
+ let url = null;
64
+ // @TODO: Allow ConnectionInfo to override some of these values
65
+ const options = {
66
+ method: 'GET',
67
+ };
68
+ let allow304 = false;
69
+ let timeout = 2 * 60 * 1000;
70
+ if (typeof connection === 'string') {
71
+ url = connection;
72
+ }
73
+ else if (typeof connection === 'object') {
74
+ if (connection == null || connection.url == null) {
75
+ logger.throwArgumentError('missing URL', 'connection.url', connection);
76
+ }
77
+ url = connection.url;
78
+ if (typeof connection.timeout === 'number' && connection.timeout > 0) {
79
+ timeout = connection.timeout;
80
+ }
81
+ if (connection.headers) {
82
+ for (const key in connection.headers) {
83
+ headers[key.toLowerCase()] = {
84
+ key: key,
85
+ value: String(connection.headers[key]),
86
+ };
87
+ if (['if-none-match', 'if-modified-since'].indexOf(key.toLowerCase()) >= 0) {
88
+ allow304 = true;
89
+ }
90
+ }
91
+ }
92
+ options.allowGzip = !!connection.allowGzip;
93
+ if (connection.user != null && connection.password != null) {
94
+ if (url.substring(0, 6) !== 'https:' &&
95
+ connection.allowInsecureAuthentication !== true) {
96
+ logger.throwError('basic authentication requires a secure https url', logger_1.Logger.errors.INVALID_ARGUMENT, {
97
+ argument: 'url',
98
+ url: url,
99
+ user: connection.user,
100
+ password: '[REDACTED]',
101
+ });
102
+ }
103
+ const authorization = connection.user + ':' + connection.password;
104
+ headers['authorization'] = {
105
+ key: 'Authorization',
106
+ value: 'Basic ' + (0, base64_1.encode)((0, strings_1.toUtf8Bytes)(authorization)),
107
+ };
108
+ }
109
+ if (connection.skipFetchSetup != null) {
110
+ options.skipFetchSetup = !!connection.skipFetchSetup;
111
+ }
112
+ if (connection.fetchOptions != null) {
113
+ options.fetchOptions = (0, properties_1.shallowCopy)(connection.fetchOptions);
114
+ }
115
+ if (connection.agents != null) {
116
+ options.agents = connection.agents;
117
+ }
118
+ }
119
+ const reData = new RegExp('^data:([^;:]*)?(;base64)?,(.*)$', 'i');
120
+ const dataMatch = url ? url.match(reData) : null;
121
+ if (dataMatch) {
122
+ try {
123
+ const response = {
124
+ statusCode: 200,
125
+ statusMessage: 'OK',
126
+ headers: { 'content-type': dataMatch[1] || 'text/plain' },
127
+ body: dataMatch[2]
128
+ ? (0, base64_1.decode)(dataMatch[3])
129
+ : unpercent(dataMatch[3]),
130
+ };
131
+ let result = response.body;
132
+ if (processFunc) {
133
+ result = processFunc(response.body, response);
134
+ }
135
+ return Promise.resolve(result);
136
+ }
137
+ catch (error) {
138
+ logger.throwError('processing response error', logger_1.Logger.errors.SERVER_ERROR, {
139
+ body: bodyify(dataMatch[1], dataMatch[2]),
140
+ error: error,
141
+ requestBody: null,
142
+ requestMethod: 'GET',
143
+ url: url,
144
+ });
145
+ }
146
+ }
147
+ if (body) {
148
+ options.method = 'POST';
149
+ options.body = body;
150
+ if (headers['content-type'] == null) {
151
+ headers['content-type'] = {
152
+ key: 'Content-Type',
153
+ value: 'application/octet-stream',
154
+ };
155
+ }
156
+ if (headers['content-length'] == null) {
157
+ headers['content-length'] = {
158
+ key: 'Content-Length',
159
+ value: String(body.length),
160
+ };
161
+ }
162
+ }
163
+ const flatHeaders = {};
164
+ Object.keys(headers).forEach((key) => {
165
+ const header = headers[key];
166
+ flatHeaders[header.key] = header.value;
167
+ });
168
+ options.headers = flatHeaders;
169
+ const runningTimeout = (function () {
170
+ let timer = null;
171
+ const promise = new Promise(function (resolve, reject) {
172
+ if (timeout) {
173
+ timer = setTimeout(() => {
174
+ if (timer == null) {
175
+ return;
176
+ }
177
+ timer = null;
178
+ reject(logger.makeError('timeout', logger_1.Logger.errors.TIMEOUT, {
179
+ requestBody: bodyify(options.body, flatHeaders['content-type']),
180
+ requestMethod: options.method,
181
+ timeout: timeout,
182
+ url: url,
183
+ }));
184
+ }, timeout);
185
+ }
186
+ });
187
+ const cancel = function () {
188
+ if (timer == null) {
189
+ return;
190
+ }
191
+ clearTimeout(timer);
192
+ timer = null;
193
+ };
194
+ return { promise, cancel };
195
+ })();
196
+ const runningFetch = (async function () {
197
+ for (let attempt = 0; attempt < attemptLimit; attempt++) {
198
+ let response = null;
199
+ try {
200
+ response = await (0, geturl_1.getUrl)(url, options);
201
+ if (attempt < attemptLimit) {
202
+ if (response.statusCode === 301 || response.statusCode === 302) {
203
+ // Redirection; for now we only support absolute locataions
204
+ const location = response.headers.location || '';
205
+ if (options.method === 'GET' && location.match(/^https:/)) {
206
+ url = response.headers.location;
207
+ continue;
208
+ }
209
+ }
210
+ else if (response.statusCode === 429) {
211
+ // Exponential back-off throttling
212
+ let tryAgain = true;
213
+ if (throttleCallback) {
214
+ tryAgain = await throttleCallback(attempt, url);
215
+ }
216
+ if (tryAgain) {
217
+ let stall = 0;
218
+ const retryAfter = response.headers['retry-after'];
219
+ if (typeof retryAfter === 'string' &&
220
+ retryAfter.match(/^[1-9][0-9]*$/)) {
221
+ stall = parseInt(retryAfter) * 1000;
222
+ }
223
+ else {
224
+ stall =
225
+ throttleSlotInterval *
226
+ parseInt(String(Math.random() * Math.pow(2, attempt)));
227
+ }
228
+ //console.log("Stalling 429");
229
+ await staller(stall);
230
+ continue;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ catch (error) {
236
+ response = error.response;
237
+ if (response == null) {
238
+ runningTimeout.cancel();
239
+ logger.throwError('missing response', logger_1.Logger.errors.SERVER_ERROR, {
240
+ requestBody: bodyify(options.body, flatHeaders['content-type']),
241
+ requestMethod: options.method,
242
+ serverError: error,
243
+ url: url,
244
+ });
245
+ }
246
+ }
247
+ let body = response.body;
248
+ if (allow304 && response.statusCode === 304) {
249
+ body = null;
250
+ }
251
+ else if (!errorPassThrough &&
252
+ (response.statusCode < 200 || response.statusCode >= 300)) {
253
+ runningTimeout.cancel();
254
+ logger.throwError('bad response', logger_1.Logger.errors.SERVER_ERROR, {
255
+ status: response.statusCode,
256
+ headers: response.headers,
257
+ body: bodyify(body, response.headers ? response.headers['content-type'] : null),
258
+ requestBody: bodyify(options.body, flatHeaders['content-type']),
259
+ requestMethod: options.method,
260
+ url: url,
261
+ });
262
+ }
263
+ if (processFunc) {
264
+ try {
265
+ const result = await processFunc(body, response);
266
+ runningTimeout.cancel();
267
+ return result;
268
+ }
269
+ catch (error) {
270
+ // Allow the processFunc to trigger a throttle
271
+ if (error.throttleRetry && attempt < attemptLimit) {
272
+ let tryAgain = true;
273
+ if (throttleCallback) {
274
+ tryAgain = await throttleCallback(attempt, url);
275
+ }
276
+ if (tryAgain) {
277
+ const timeout = throttleSlotInterval *
278
+ parseInt(String(Math.random() * Math.pow(2, attempt)));
279
+ //console.log("Stalling callback");
280
+ await staller(timeout);
281
+ continue;
282
+ }
283
+ }
284
+ runningTimeout.cancel();
285
+ logger.throwError('processing response error', logger_1.Logger.errors.SERVER_ERROR, {
286
+ body: bodyify(body, response.headers ? response.headers['content-type'] : null),
287
+ error: error,
288
+ requestBody: bodyify(options.body, flatHeaders['content-type']),
289
+ requestMethod: options.method,
290
+ url: url,
291
+ });
292
+ }
293
+ }
294
+ runningTimeout.cancel();
295
+ // If we had a processFunc, it either returned a T or threw above.
296
+ // The "body" is now a Uint8Array.
297
+ return body;
298
+ }
299
+ return logger.throwError('failed response', logger_1.Logger.errors.SERVER_ERROR, {
300
+ requestBody: bodyify(options.body, flatHeaders['content-type']),
301
+ requestMethod: options.method,
302
+ url: url,
303
+ });
304
+ })();
305
+ return Promise.race([runningTimeout.promise, runningFetch]);
306
+ }
307
+ exports._fetchData = _fetchData;
308
+ function fetchJson(connection, json, processFunc) {
309
+ let processJsonFunc = (value, response) => {
310
+ let result = null;
311
+ if (value != null) {
312
+ try {
313
+ result = JSON.parse((0, strings_1.toUtf8String)(value));
314
+ }
315
+ catch (error) {
316
+ logger.throwError('invalid JSON', logger_1.Logger.errors.SERVER_ERROR, {
317
+ body: value,
318
+ error: error,
319
+ });
320
+ }
321
+ }
322
+ if (processFunc) {
323
+ result = processFunc(result, response);
324
+ }
325
+ return result;
326
+ };
327
+ // If we have json to send, we must
328
+ // - add content-type of application/json (unless already overridden)
329
+ // - convert the json to bytes
330
+ let body = null;
331
+ if (json != null) {
332
+ body = (0, strings_1.toUtf8Bytes)(json);
333
+ // Create a connection with the content-type set for JSON
334
+ const updated = typeof connection === 'string'
335
+ ? { url: connection }
336
+ : (0, properties_1.shallowCopy)(connection);
337
+ if (updated.headers) {
338
+ const hasContentType = Object.keys(updated.headers).filter((k) => k.toLowerCase() === 'content-type').length !== 0;
339
+ if (!hasContentType) {
340
+ updated.headers = (0, properties_1.shallowCopy)(updated.headers);
341
+ updated.headers['content-type'] = 'application/json';
342
+ }
343
+ }
344
+ else {
345
+ updated.headers = { 'content-type': 'application/json' };
346
+ }
347
+ connection = updated;
348
+ }
349
+ return _fetchData(connection, body, processJsonFunc);
350
+ }
351
+ exports.fetchJson = fetchJson;
352
+ function poll(func, options) {
353
+ if (!options) {
354
+ options = {};
355
+ }
356
+ options = (0, properties_1.shallowCopy)(options);
357
+ if (options.floor == null) {
358
+ options.floor = 0;
359
+ }
360
+ if (options.ceiling == null) {
361
+ options.ceiling = 10000;
362
+ }
363
+ if (options.interval == null) {
364
+ options.interval = 250;
365
+ }
366
+ return new Promise(function (resolve, reject) {
367
+ let timer = null;
368
+ let done = false;
369
+ // Returns true if cancel was successful. Unsuccessful cancel means we're already done.
370
+ const cancel = () => {
371
+ if (done) {
372
+ return false;
373
+ }
374
+ done = true;
375
+ if (timer) {
376
+ clearTimeout(timer);
377
+ }
378
+ return true;
379
+ };
380
+ if (options.timeout) {
381
+ timer = setTimeout(() => {
382
+ if (cancel()) {
383
+ reject(new Error('timeout'));
384
+ }
385
+ }, options.timeout);
386
+ }
387
+ const retryLimit = options.retryLimit;
388
+ let attempt = 0;
389
+ function check() {
390
+ return func().then(function (result) {
391
+ // If we have a result, or are allowed null then we're done
392
+ if (result !== undefined) {
393
+ if (cancel()) {
394
+ resolve(result);
395
+ }
396
+ }
397
+ else if (options.oncePoll) {
398
+ options.oncePoll.once('poll', check);
399
+ }
400
+ else if (options.onceBlock) {
401
+ options.onceBlock.once('block', check);
402
+ // Otherwise, exponential back-off (up to 10s) our next request
403
+ }
404
+ else if (!done) {
405
+ attempt++;
406
+ if (attempt > retryLimit) {
407
+ if (cancel()) {
408
+ reject(new Error('retry limit reached'));
409
+ }
410
+ return;
411
+ }
412
+ let timeout = options.interval *
413
+ parseInt(String(Math.random() * Math.pow(2, attempt)));
414
+ if (timeout < options.floor) {
415
+ timeout = options.floor;
416
+ }
417
+ if (timeout > options.ceiling) {
418
+ timeout = options.ceiling;
419
+ }
420
+ setTimeout(check, timeout);
421
+ }
422
+ return null;
423
+ }, function (error) {
424
+ if (cancel()) {
425
+ reject(error);
426
+ }
427
+ });
428
+ }
429
+ check();
430
+ });
431
+ }
432
+ exports.poll = poll;
433
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/ethereum/ethers/web/index.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable */\n'use strict';\n\nimport http from 'http';\nimport https from 'https';\nimport {\n decode as base64Decode,\n encode as base64Encode,\n} from '@ethersproject/base64';\nimport { hexlify, isBytesLike } from '@ethersproject/bytes';\nimport { shallowCopy } from '@ethersproject/properties';\nimport { toUtf8Bytes, toUtf8String } from '@ethersproject/strings';\n\nimport { Logger } from '@ethersproject/logger';\nimport { version } from './_version';\nconst logger = new Logger(version);\n\nimport { getUrl, GetUrlResponse, Options } from './geturl';\n\nfunction staller(duration: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, duration);\n });\n}\n\nfunction bodyify(value: any, type: string): string {\n if (value == null) {\n return null;\n }\n\n if (typeof value === 'string') {\n return value;\n }\n\n if (isBytesLike(value)) {\n if (\n type &&\n (type.split('/')[0] === 'text' ||\n type.split(';')[0].trim() === 'application/json')\n ) {\n try {\n return toUtf8String(value);\n } catch (error) {}\n }\n return hexlify(value);\n }\n\n return value;\n}\n\n// Exported Types\nexport type ConnectionInfo = {\n url: string;\n headers?: { [key: string]: string | number };\n\n user?: string;\n password?: string;\n\n allowInsecureAuthentication?: boolean;\n allowGzip?: boolean;\n\n throttleLimit?: number;\n throttleSlotInterval?: number;\n throttleCallback?: (attempt: number, url: string) => Promise<boolean>;\n\n skipFetchSetup?: boolean;\n fetchOptions?: Record<string, string>;\n errorPassThrough?: boolean;\n\n timeout?: number;\n\n agents?: {\n http?: http.Agent;\n https?: https.Agent;\n };\n};\n\nexport interface OnceBlockable {\n once(eventName: 'block', handler: () => void): void;\n}\n\nexport interface OncePollable {\n once(eventName: 'poll', handler: () => void): void;\n}\n\nexport type PollOptions = {\n timeout?: number;\n floor?: number;\n ceiling?: number;\n interval?: number;\n retryLimit?: number;\n onceBlock?: OnceBlockable;\n oncePoll?: OncePollable;\n};\n\nexport type FetchJsonResponse = {\n statusCode: number;\n headers: { [header: string]: string };\n};\n\ntype Header = { key: string; value: string };\n\nfunction unpercent(value: string): Uint8Array {\n return toUtf8Bytes(\n value.replace(/%([0-9a-f][0-9a-f])/gi, (all, code) => {\n return String.fromCharCode(parseInt(code, 16));\n }),\n );\n}\n\n// This API is still a work in progress; the future changes will likely be:\n// - ConnectionInfo => FetchDataRequest<T = any>\n// - FetchDataRequest.body? = string | Uint8Array | { contentType: string, data: string | Uint8Array }\n// - If string => text/plain, Uint8Array => application/octet-stream (if content-type unspecified)\n// - FetchDataRequest.processFunc = (body: Uint8Array, response: FetchDataResponse) => T\n// For this reason, it should be considered internal until the API is finalized\nexport function _fetchData<T = Uint8Array>(\n connection: string | ConnectionInfo,\n body?: Uint8Array,\n processFunc?: (value: Uint8Array, response: FetchJsonResponse) => T,\n): Promise<T> {\n // How many times to retry in the event of a throttle\n const attemptLimit =\n typeof connection === 'object' && connection.throttleLimit != null\n ? connection.throttleLimit\n : 12;\n logger.assertArgument(\n attemptLimit > 0 && attemptLimit % 1 === 0,\n 'invalid connection throttle limit',\n 'connection.throttleLimit',\n attemptLimit,\n );\n\n const throttleCallback =\n typeof connection === 'object' ? connection.throttleCallback : null;\n const throttleSlotInterval =\n typeof connection === 'object' &&\n typeof connection.throttleSlotInterval === 'number'\n ? connection.throttleSlotInterval\n : 100;\n logger.assertArgument(\n throttleSlotInterval > 0 && throttleSlotInterval % 1 === 0,\n 'invalid connection throttle slot interval',\n 'connection.throttleSlotInterval',\n throttleSlotInterval,\n );\n\n const errorPassThrough =\n typeof connection === 'object' ? !!connection.errorPassThrough : false;\n\n const headers: { [key: string]: Header } = {};\n\n let url: string = null;\n\n // @TODO: Allow ConnectionInfo to override some of these values\n const options: Options = {\n method: 'GET',\n };\n\n let allow304 = false;\n\n let timeout = 2 * 60 * 1000;\n\n if (typeof connection === 'string') {\n url = connection;\n } else if (typeof connection === 'object') {\n if (connection == null || connection.url == null) {\n logger.throwArgumentError('missing URL', 'connection.url', connection);\n }\n\n url = connection.url;\n\n if (typeof connection.timeout === 'number' && connection.timeout > 0) {\n timeout = connection.timeout;\n }\n\n if (connection.headers) {\n for (const key in connection.headers) {\n headers[key.toLowerCase()] = {\n key: key,\n value: String(connection.headers[key]),\n };\n if (\n ['if-none-match', 'if-modified-since'].indexOf(key.toLowerCase()) >= 0\n ) {\n allow304 = true;\n }\n }\n }\n\n options.allowGzip = !!connection.allowGzip;\n\n if (connection.user != null && connection.password != null) {\n if (\n url.substring(0, 6) !== 'https:' &&\n connection.allowInsecureAuthentication !== true\n ) {\n logger.throwError(\n 'basic authentication requires a secure https url',\n Logger.errors.INVALID_ARGUMENT,\n {\n argument: 'url',\n url: url,\n user: connection.user,\n password: '[REDACTED]',\n },\n );\n }\n\n const authorization = connection.user + ':' + connection.password;\n headers['authorization'] = {\n key: 'Authorization',\n value: 'Basic ' + base64Encode(toUtf8Bytes(authorization)),\n };\n }\n\n if (connection.skipFetchSetup != null) {\n options.skipFetchSetup = !!connection.skipFetchSetup;\n }\n\n if (connection.fetchOptions != null) {\n options.fetchOptions = shallowCopy(connection.fetchOptions);\n }\n\n if (connection.agents != null) {\n options.agents = connection.agents;\n }\n }\n\n const reData = new RegExp('^data:([^;:]*)?(;base64)?,(.*)$', 'i');\n const dataMatch = url ? url.match(reData) : null;\n if (dataMatch) {\n try {\n const response = {\n statusCode: 200,\n statusMessage: 'OK',\n headers: { 'content-type': dataMatch[1] || 'text/plain' },\n body: dataMatch[2]\n ? base64Decode(dataMatch[3])\n : unpercent(dataMatch[3]),\n };\n\n let result: T = <T>(<unknown>response.body);\n if (processFunc) {\n result = processFunc(response.body, response);\n }\n return Promise.resolve(<T>(<unknown>result));\n } catch (error) {\n logger.throwError(\n 'processing response error',\n Logger.errors.SERVER_ERROR,\n {\n body: bodyify(dataMatch[1], dataMatch[2]),\n error: error,\n requestBody: null,\n requestMethod: 'GET',\n url: url,\n },\n );\n }\n }\n\n if (body) {\n options.method = 'POST';\n options.body = body;\n if (headers['content-type'] == null) {\n headers['content-type'] = {\n key: 'Content-Type',\n value: 'application/octet-stream',\n };\n }\n if (headers['content-length'] == null) {\n headers['content-length'] = {\n key: 'Content-Length',\n value: String(body.length),\n };\n }\n }\n\n const flatHeaders: { [key: string]: string } = {};\n Object.keys(headers).forEach((key) => {\n const header = headers[key];\n flatHeaders[header.key] = header.value;\n });\n options.headers = flatHeaders;\n\n const runningTimeout = (function () {\n let timer: NodeJS.Timer = null;\n const promise: Promise<never> = new Promise(function (resolve, reject) {\n if (timeout) {\n timer = setTimeout(() => {\n if (timer == null) {\n return;\n }\n timer = null;\n\n reject(\n logger.makeError('timeout', Logger.errors.TIMEOUT, {\n requestBody: bodyify(options.body, flatHeaders['content-type']),\n requestMethod: options.method,\n timeout: timeout,\n url: url,\n }),\n );\n }, timeout);\n }\n });\n\n const cancel = function () {\n if (timer == null) {\n return;\n }\n clearTimeout(timer);\n timer = null;\n };\n\n return { promise, cancel };\n })();\n\n const runningFetch = (async function () {\n for (let attempt = 0; attempt < attemptLimit; attempt++) {\n let response: GetUrlResponse = null;\n\n try {\n response = await getUrl(url, options);\n\n if (attempt < attemptLimit) {\n if (response.statusCode === 301 || response.statusCode === 302) {\n // Redirection; for now we only support absolute locataions\n const location = response.headers.location || '';\n if (options.method === 'GET' && location.match(/^https:/)) {\n url = response.headers.location;\n continue;\n }\n } else if (response.statusCode === 429) {\n // Exponential back-off throttling\n let tryAgain = true;\n if (throttleCallback) {\n tryAgain = await throttleCallback(attempt, url);\n }\n\n if (tryAgain) {\n let stall = 0;\n\n const retryAfter = response.headers['retry-after'];\n if (\n typeof retryAfter === 'string' &&\n retryAfter.match(/^[1-9][0-9]*$/)\n ) {\n stall = parseInt(retryAfter) * 1000;\n } else {\n stall =\n throttleSlotInterval *\n parseInt(String(Math.random() * Math.pow(2, attempt)));\n }\n\n //console.log(\"Stalling 429\");\n await staller(stall);\n continue;\n }\n }\n }\n } catch (error) {\n response = (<any>error).response;\n if (response == null) {\n runningTimeout.cancel();\n logger.throwError('missing response', Logger.errors.SERVER_ERROR, {\n requestBody: bodyify(options.body, flatHeaders['content-type']),\n requestMethod: options.method,\n serverError: error,\n url: url,\n });\n }\n }\n\n let body = response.body;\n\n if (allow304 && response.statusCode === 304) {\n body = null;\n } else if (\n !errorPassThrough &&\n (response.statusCode < 200 || response.statusCode >= 300)\n ) {\n runningTimeout.cancel();\n logger.throwError('bad response', Logger.errors.SERVER_ERROR, {\n status: response.statusCode,\n headers: response.headers,\n body: bodyify(\n body,\n response.headers ? response.headers['content-type'] : null,\n ),\n requestBody: bodyify(options.body, flatHeaders['content-type']),\n requestMethod: options.method,\n url: url,\n });\n }\n\n if (processFunc) {\n try {\n const result = await processFunc(body, response);\n runningTimeout.cancel();\n return result;\n } catch (error) {\n // Allow the processFunc to trigger a throttle\n if (error.throttleRetry && attempt < attemptLimit) {\n let tryAgain = true;\n if (throttleCallback) {\n tryAgain = await throttleCallback(attempt, url);\n }\n\n if (tryAgain) {\n const timeout =\n throttleSlotInterval *\n parseInt(String(Math.random() * Math.pow(2, attempt)));\n //console.log(\"Stalling callback\");\n await staller(timeout);\n continue;\n }\n }\n\n runningTimeout.cancel();\n logger.throwError(\n 'processing response error',\n Logger.errors.SERVER_ERROR,\n {\n body: bodyify(\n body,\n response.headers ? response.headers['content-type'] : null,\n ),\n error: error,\n requestBody: bodyify(options.body, flatHeaders['content-type']),\n requestMethod: options.method,\n url: url,\n },\n );\n }\n }\n\n runningTimeout.cancel();\n\n // If we had a processFunc, it either returned a T or threw above.\n // The \"body\" is now a Uint8Array.\n return <T>(<unknown>body);\n }\n\n return logger.throwError('failed response', Logger.errors.SERVER_ERROR, {\n requestBody: bodyify(options.body, flatHeaders['content-type']),\n requestMethod: options.method,\n url: url,\n });\n })();\n\n return Promise.race([runningTimeout.promise, runningFetch]);\n}\n\nexport function fetchJson(\n connection: string | ConnectionInfo,\n json?: string,\n processFunc?: (value: any, response: FetchJsonResponse) => any,\n): Promise<any> {\n let processJsonFunc = (value: Uint8Array, response: FetchJsonResponse) => {\n let result: any = null;\n if (value != null) {\n try {\n result = JSON.parse(toUtf8String(value));\n } catch (error) {\n logger.throwError('invalid JSON', Logger.errors.SERVER_ERROR, {\n body: value,\n error: error,\n });\n }\n }\n\n if (processFunc) {\n result = processFunc(result, response);\n }\n\n return result;\n };\n\n // If we have json to send, we must\n // - add content-type of application/json (unless already overridden)\n // - convert the json to bytes\n let body: Uint8Array = null;\n if (json != null) {\n body = toUtf8Bytes(json);\n\n // Create a connection with the content-type set for JSON\n const updated: ConnectionInfo =\n typeof connection === 'string'\n ? { url: connection }\n : shallowCopy(connection);\n if (updated.headers) {\n const hasContentType =\n Object.keys(updated.headers).filter(\n (k) => k.toLowerCase() === 'content-type',\n ).length !== 0;\n if (!hasContentType) {\n updated.headers = shallowCopy(updated.headers);\n updated.headers['content-type'] = 'application/json';\n }\n } else {\n updated.headers = { 'content-type': 'application/json' };\n }\n connection = updated;\n }\n\n return _fetchData<any>(connection, body, processJsonFunc);\n}\n\nexport function poll<T>(\n func: () => Promise<T>,\n options?: PollOptions,\n): Promise<T> {\n if (!options) {\n options = {};\n }\n options = shallowCopy(options);\n if (options.floor == null) {\n options.floor = 0;\n }\n if (options.ceiling == null) {\n options.ceiling = 10000;\n }\n if (options.interval == null) {\n options.interval = 250;\n }\n\n return new Promise(function (resolve, reject) {\n let timer: NodeJS.Timer = null;\n let done: boolean = false;\n\n // Returns true if cancel was successful. Unsuccessful cancel means we're already done.\n const cancel = (): boolean => {\n if (done) {\n return false;\n }\n done = true;\n if (timer) {\n clearTimeout(timer);\n }\n return true;\n };\n\n if (options.timeout) {\n timer = setTimeout(() => {\n if (cancel()) {\n reject(new Error('timeout'));\n }\n }, options.timeout);\n }\n\n const retryLimit = options.retryLimit;\n\n let attempt = 0;\n function check() {\n return func().then(\n function (result) {\n // If we have a result, or are allowed null then we're done\n if (result !== undefined) {\n if (cancel()) {\n resolve(result);\n }\n } else if (options.oncePoll) {\n options.oncePoll.once('poll', check);\n } else if (options.onceBlock) {\n options.onceBlock.once('block', check);\n\n // Otherwise, exponential back-off (up to 10s) our next request\n } else if (!done) {\n attempt++;\n if (attempt > retryLimit) {\n if (cancel()) {\n reject(new Error('retry limit reached'));\n }\n return;\n }\n\n let timeout =\n options.interval *\n parseInt(String(Math.random() * Math.pow(2, attempt)));\n if (timeout < options.floor) {\n timeout = options.floor;\n }\n if (timeout > options.ceiling) {\n timeout = options.ceiling;\n }\n\n setTimeout(check, timeout);\n }\n\n return null;\n },\n function (error) {\n if (cancel()) {\n reject(error);\n }\n },\n );\n }\n check();\n });\n}\n"]}
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import http from 'http';
4
+ import https from 'https';
5
+ export declare type GetUrlResponse = {
6
+ statusCode: number;
7
+ statusMessage: string;
8
+ headers: {
9
+ [key: string]: string;
10
+ };
11
+ body: Uint8Array;
12
+ };
13
+ export declare type Options = {
14
+ method?: string;
15
+ allowGzip?: boolean;
16
+ body?: Uint8Array;
17
+ headers?: {
18
+ [key: string]: string;
19
+ };
20
+ skipFetchSetup?: boolean;
21
+ fetchOptions?: Record<string, string>;
22
+ agents?: {
23
+ http?: http.Agent;
24
+ https?: https.Agent;
25
+ };
26
+ };
@@ -0,0 +1,4 @@
1
+ /* eslint-disable */
2
+ 'use strict';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/ethereum/ethers/web/types.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,YAAY,CAAC","sourcesContent":["/* eslint-disable */\n'use strict';\nimport http from 'http';\nimport https from 'https';\n\nexport type GetUrlResponse = {\n statusCode: number;\n statusMessage: string;\n headers: { [key: string]: string };\n body: Uint8Array;\n};\n\nexport type Options = {\n method?: string;\n allowGzip?: boolean;\n body?: Uint8Array;\n headers?: { [key: string]: string };\n skipFetchSetup?: boolean;\n fetchOptions?: Record<string, string>;\n agents?: {\n http?: http.Agent;\n https?: https.Agent;\n };\n};\n"]}
@@ -50,6 +50,10 @@ let BlockDispatcherService = class BlockDispatcherService extends base_block_dis
50
50
  this.processQueue.abort();
51
51
  }
52
52
  enqueueBlocks(cleanedBlocks, latestBufferHeight) {
53
+ this.eventEmitter.emit('enqueueBlocks', cleanedBlocks.length);
54
+ if (cleanedBlocks.length) {
55
+ this.eventEmitter.emit('filteringBlocks', cleanedBlocks[cleanedBlocks.length - 1]);
56
+ }
53
57
  // // In the case where factors of batchSize is equal to bypassBlock or when cleanedBatchBlocks is []
54
58
  // // to ensure block is bypassed, latestBufferHeight needs to be manually set
55
59
  // If cleanedBlocks = []
@@ -1 +1 @@
1
- {"version":3,"file":"block-dispatcher.service.js","sourceRoot":"","sources":["../../../src/indexer/blockDispatcher/block-dispatcher.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2021 OnFinality Limited authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Injectable, OnApplicationShutdown } from '@nestjs/common';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport {\n ApiService,\n getLogger,\n NodeConfig,\n IndexerEvent,\n delay,\n profilerWrap,\n AutoQueue,\n Queue,\n} from '@subql/node-core';\nimport { last } from 'lodash';\nimport { EthereumApiService } from '../../ethereum';\nimport { IndexerManager } from '../indexer.manager';\nimport { ProjectService } from '../project.service';\nimport { BaseBlockDispatcher } from './base-block-dispatcher';\n\nconst logger = getLogger('BlockDispatcherService');\n\n/**\n * @description Intended to behave the same as WorkerBlockDispatcherService but doesn't use worker threads or any parallel processing\n */\n@Injectable()\nexport class BlockDispatcherService\n extends BaseBlockDispatcher<Queue<number>>\n implements OnApplicationShutdown\n{\n private processQueue: AutoQueue<void>;\n\n private fetching = false;\n private isShutdown = false;\n private fetchBlocksBatches: EthereumApiService['api']['fetchBlocks'];\n\n constructor(\n private apiService: ApiService,\n nodeConfig: NodeConfig,\n private indexerManager: IndexerManager,\n eventEmitter: EventEmitter2,\n projectService: ProjectService,\n ) {\n super(\n nodeConfig,\n eventEmitter,\n projectService,\n new Queue(nodeConfig.batchSize * 3),\n );\n this.processQueue = new AutoQueue(nodeConfig.batchSize * 3);\n\n const fetchBlocks = this.apiService.api.fetchBlocks.bind(\n this.apiService.api,\n );\n if (this.nodeConfig.profiler) {\n this.fetchBlocksBatches = profilerWrap(\n fetchBlocks,\n 'EthereumUtil',\n 'fetchBlocksBatches',\n );\n } else {\n this.fetchBlocksBatches = fetchBlocks;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async init(\n onDynamicDsCreated: (height: number) => Promise<void>,\n ): Promise<void> {\n this.onDynamicDsCreated = onDynamicDsCreated;\n const blockAmount = await this.projectService.getProcessedBlockCount();\n this.setProcessedBlockCount(blockAmount ?? 0);\n }\n\n onApplicationShutdown(): void {\n this.isShutdown = true;\n this.processQueue.abort();\n }\n\n enqueueBlocks(cleanedBlocks: number[], latestBufferHeight?: number): void {\n // // In the case where factors of batchSize is equal to bypassBlock or when cleanedBatchBlocks is []\n // // to ensure block is bypassed, latestBufferHeight needs to be manually set\n // If cleanedBlocks = []\n if (!!latestBufferHeight && !cleanedBlocks.length) {\n this.latestBufferedHeight = latestBufferHeight;\n return;\n }\n\n logger.info(\n `Enqueueing blocks ${cleanedBlocks[0]}...${last(cleanedBlocks)}, total ${\n cleanedBlocks.length\n } blocks`,\n );\n\n this.queue.putMany(cleanedBlocks);\n\n this.latestBufferedHeight = latestBufferHeight ?? last(cleanedBlocks);\n void this.fetchBlocksFromQueue().catch((e) => {\n logger.error(e, 'Failed to fetch blocks from queue');\n if (!this.isShutdown) {\n process.exit(1);\n }\n });\n }\n\n flushQueue(height: number): void {\n super.flushQueue(height);\n this.processQueue.flush();\n }\n\n private async fetchBlocksFromQueue(): Promise<void> {\n if (this.fetching || this.isShutdown) return;\n // Process queue is full, no point in fetching more blocks\n // if (this.processQueue.freeSpace < this.nodeConfig.batchSize) return;\n\n this.fetching = true;\n\n try {\n while (!this.isShutdown) {\n const blockNums = this.queue.takeMany(\n Math.min(this.nodeConfig.batchSize, this.processQueue.freeSpace),\n );\n // Used to compare before and after as a way to check if queue was flushed\n const bufferedHeight = this._latestBufferedHeight;\n\n // Queue is empty\n if (!blockNums.length) {\n // The process queue might be full so no block nums were taken, wait and try again\n if (this.queue.size) {\n await delay(1);\n continue;\n }\n break;\n }\n\n logger.info(\n `fetch block [${blockNums[0]},${\n blockNums[blockNums.length - 1]\n }], total ${blockNums.length} blocks`,\n );\n\n const blocks = await this.fetchBlocksBatches(blockNums);\n\n // Check if the queues have been flushed between queue.takeMany and fetchBlocksBatches resolving\n // Peeking the queue is because the latestBufferedHeight could have regrown since fetching block\n if (\n bufferedHeight > this._latestBufferedHeight ||\n this.queue.peek() < Math.min(...blockNums)\n ) {\n logger.info(`Queue was reset for new DS, discarding fetched blocks`);\n continue;\n }\n\n const blockTasks = blocks.map((block) => async () => {\n const height = block.blockHeight;\n try {\n this.preProcessBlock(height);\n\n const processBlockResponse = await this.indexerManager.indexBlock(\n block,\n );\n\n await this.postProcessBlock(height, processBlockResponse);\n } catch (e) {\n if (this.isShutdown) {\n return;\n }\n logger.error(\n e,\n `failed to index block at height ${height} ${\n e.handler ? `${e.handler}(${e.stack ?? ''})` : ''\n }`,\n );\n throw e;\n }\n });\n\n // There can be enough of a delay after fetching blocks that shutdown could now be true\n if (this.isShutdown) break;\n\n this.processQueue.putMany(blockTasks);\n\n this.eventEmitter.emit(IndexerEvent.BlockQueueSize, {\n value: this.processQueue.size,\n });\n }\n } finally {\n this.fetching = false;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"block-dispatcher.service.js","sourceRoot":"","sources":["../../../src/indexer/blockDispatcher/block-dispatcher.service.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2020-2021 OnFinality Limited authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Injectable, OnApplicationShutdown } from '@nestjs/common';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport {\n ApiService,\n getLogger,\n NodeConfig,\n IndexerEvent,\n delay,\n profilerWrap,\n AutoQueue,\n Queue,\n} from '@subql/node-core';\nimport { last } from 'lodash';\nimport { EthereumApiService } from '../../ethereum';\nimport { IndexerManager } from '../indexer.manager';\nimport { ProjectService } from '../project.service';\nimport { BaseBlockDispatcher } from './base-block-dispatcher';\n\nconst logger = getLogger('BlockDispatcherService');\n\n/**\n * @description Intended to behave the same as WorkerBlockDispatcherService but doesn't use worker threads or any parallel processing\n */\n@Injectable()\nexport class BlockDispatcherService\n extends BaseBlockDispatcher<Queue<number>>\n implements OnApplicationShutdown\n{\n private processQueue: AutoQueue<void>;\n\n private fetching = false;\n private isShutdown = false;\n private fetchBlocksBatches: EthereumApiService['api']['fetchBlocks'];\n\n constructor(\n private apiService: ApiService,\n nodeConfig: NodeConfig,\n private indexerManager: IndexerManager,\n eventEmitter: EventEmitter2,\n projectService: ProjectService,\n ) {\n super(\n nodeConfig,\n eventEmitter,\n projectService,\n new Queue(nodeConfig.batchSize * 3),\n );\n this.processQueue = new AutoQueue(nodeConfig.batchSize * 3);\n\n const fetchBlocks = this.apiService.api.fetchBlocks.bind(\n this.apiService.api,\n );\n if (this.nodeConfig.profiler) {\n this.fetchBlocksBatches = profilerWrap(\n fetchBlocks,\n 'EthereumUtil',\n 'fetchBlocksBatches',\n );\n } else {\n this.fetchBlocksBatches = fetchBlocks;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async init(\n onDynamicDsCreated: (height: number) => Promise<void>,\n ): Promise<void> {\n this.onDynamicDsCreated = onDynamicDsCreated;\n const blockAmount = await this.projectService.getProcessedBlockCount();\n this.setProcessedBlockCount(blockAmount ?? 0);\n }\n\n onApplicationShutdown(): void {\n this.isShutdown = true;\n this.processQueue.abort();\n }\n\n enqueueBlocks(cleanedBlocks: number[], latestBufferHeight?: number): void {\n this.eventEmitter.emit('enqueueBlocks', cleanedBlocks.length);\n if (cleanedBlocks.length) {\n this.eventEmitter.emit(\n 'filteringBlocks',\n cleanedBlocks[cleanedBlocks.length - 1],\n );\n }\n // // In the case where factors of batchSize is equal to bypassBlock or when cleanedBatchBlocks is []\n // // to ensure block is bypassed, latestBufferHeight needs to be manually set\n // If cleanedBlocks = []\n if (!!latestBufferHeight && !cleanedBlocks.length) {\n this.latestBufferedHeight = latestBufferHeight;\n return;\n }\n\n logger.info(\n `Enqueueing blocks ${cleanedBlocks[0]}...${last(cleanedBlocks)}, total ${\n cleanedBlocks.length\n } blocks`,\n );\n\n this.queue.putMany(cleanedBlocks);\n\n this.latestBufferedHeight = latestBufferHeight ?? last(cleanedBlocks);\n void this.fetchBlocksFromQueue().catch((e) => {\n logger.error(e, 'Failed to fetch blocks from queue');\n if (!this.isShutdown) {\n process.exit(1);\n }\n });\n }\n\n flushQueue(height: number): void {\n super.flushQueue(height);\n this.processQueue.flush();\n }\n\n private async fetchBlocksFromQueue(): Promise<void> {\n if (this.fetching || this.isShutdown) return;\n // Process queue is full, no point in fetching more blocks\n // if (this.processQueue.freeSpace < this.nodeConfig.batchSize) return;\n\n this.fetching = true;\n\n try {\n while (!this.isShutdown) {\n const blockNums = this.queue.takeMany(\n Math.min(this.nodeConfig.batchSize, this.processQueue.freeSpace),\n );\n // Used to compare before and after as a way to check if queue was flushed\n const bufferedHeight = this._latestBufferedHeight;\n\n // Queue is empty\n if (!blockNums.length) {\n // The process queue might be full so no block nums were taken, wait and try again\n if (this.queue.size) {\n await delay(1);\n continue;\n }\n break;\n }\n\n logger.info(\n `fetch block [${blockNums[0]},${\n blockNums[blockNums.length - 1]\n }], total ${blockNums.length} blocks`,\n );\n\n const blocks = await this.fetchBlocksBatches(blockNums);\n\n // Check if the queues have been flushed between queue.takeMany and fetchBlocksBatches resolving\n // Peeking the queue is because the latestBufferedHeight could have regrown since fetching block\n if (\n bufferedHeight > this._latestBufferedHeight ||\n this.queue.peek() < Math.min(...blockNums)\n ) {\n logger.info(`Queue was reset for new DS, discarding fetched blocks`);\n continue;\n }\n\n const blockTasks = blocks.map((block) => async () => {\n const height = block.blockHeight;\n try {\n this.preProcessBlock(height);\n\n const processBlockResponse = await this.indexerManager.indexBlock(\n block,\n );\n\n await this.postProcessBlock(height, processBlockResponse);\n } catch (e) {\n if (this.isShutdown) {\n return;\n }\n logger.error(\n e,\n `failed to index block at height ${height} ${\n e.handler ? `${e.handler}(${e.stack ?? ''})` : ''\n }`,\n );\n throw e;\n }\n });\n\n // There can be enough of a delay after fetching blocks that shutdown could now be true\n if (this.isShutdown) break;\n\n this.processQueue.putMany(blockTasks);\n\n this.eventEmitter.emit(IndexerEvent.BlockQueueSize, {\n value: this.processQueue.size,\n });\n }\n } finally {\n this.fetching = false;\n }\n }\n}\n"]}