@dedot/api 0.9.5-next.11b0ca8e.3 → 0.9.5-next.4fd5def5.41
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.
- package/cjs/extrinsic/extensions/ExtraSignedExtension.js +10 -3
- package/cjs/extrinsic/submittable/BaseSubmittableExtrinsic.js +0 -4
- package/cjs/json-rpc/group/ChainHead/ChainHead.js +14 -8
- package/cjs/storage/NewStorageQuery.js +7 -1
- package/executor/Executor.d.ts +1 -1
- package/extrinsic/extensions/ExtraSignedExtension.js +10 -3
- package/extrinsic/submittable/BaseSubmittableExtrinsic.js +0 -4
- package/json-rpc/group/ChainHead/ChainHead.js +15 -9
- package/package.json +9 -9
- package/storage/NewStorageQuery.js +8 -2
|
@@ -26,8 +26,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.ExtraSignedExtension = void 0;
|
|
27
27
|
const $ = __importStar(require("@dedot/shape"));
|
|
28
28
|
const utils_1 = require("@dedot/utils");
|
|
29
|
-
const SignedExtension_js_1 = require("./SignedExtension.js");
|
|
30
29
|
const FallbackSignedExtension_js_1 = require("./FallbackSignedExtension.js");
|
|
30
|
+
const SignedExtension_js_1 = require("./SignedExtension.js");
|
|
31
31
|
const index_js_1 = require("./known/index.js");
|
|
32
32
|
class ExtraSignedExtension extends SignedExtension_js_1.SignedExtension {
|
|
33
33
|
#signedExtensions;
|
|
@@ -83,13 +83,20 @@ class ExtraSignedExtension extends SignedExtension_js_1.SignedExtension {
|
|
|
83
83
|
* @returns boolean
|
|
84
84
|
*/
|
|
85
85
|
isRequireNoExternalInputs(extDef) {
|
|
86
|
-
return ((0, FallbackSignedExtension_js_1.isEmptyStructOrTuple)(this.registry, extDef.typeId) &&
|
|
86
|
+
return ((0, FallbackSignedExtension_js_1.isEmptyStructOrTuple)(this.registry, extDef.typeId) && // prettier-end-here
|
|
87
87
|
(0, FallbackSignedExtension_js_1.isEmptyStructOrTuple)(this.registry, extDef.additionalSigned));
|
|
88
88
|
}
|
|
89
89
|
toPayload(call = '0x') {
|
|
90
90
|
const signedExtensions = this.#signedExtensions.map((se) => se.identifier);
|
|
91
91
|
const { version } = this.registry.metadata.extrinsic;
|
|
92
|
-
|
|
92
|
+
const { signerAddress } = this.options;
|
|
93
|
+
return Object.assign({
|
|
94
|
+
address: signerAddress,
|
|
95
|
+
signedExtensions,
|
|
96
|
+
version,
|
|
97
|
+
method: call,
|
|
98
|
+
withSignedTransaction: true, // allow signer/wallet to alter transaction by default
|
|
99
|
+
}, ...this.#signedExtensions.map((se) => se.toPayload()));
|
|
93
100
|
}
|
|
94
101
|
toRawPayload(call = '0x') {
|
|
95
102
|
const payload = this.toPayload(call);
|
|
@@ -91,10 +91,6 @@ class BaseSubmittableExtrinsic extends codecs_1.Extrinsic {
|
|
|
91
91
|
if (!alteredTx.signed) {
|
|
92
92
|
throw new utils_1.DedotError('Altered transaction from signer is not signed');
|
|
93
93
|
}
|
|
94
|
-
// Signer's not allow the change the call data
|
|
95
|
-
if (alteredTx.callHex !== this.callHex) {
|
|
96
|
-
throw new utils_1.DedotError('Call data does not match, signer is not allowed to change tx call data.');
|
|
97
|
-
}
|
|
98
94
|
}
|
|
99
95
|
#getSigner(options) {
|
|
100
96
|
return options?.signer || this.client.options.signer;
|
|
@@ -22,6 +22,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
22
22
|
#recovering;
|
|
23
23
|
#blockUsage;
|
|
24
24
|
#cache;
|
|
25
|
+
#operationQueue;
|
|
25
26
|
constructor(client, options) {
|
|
26
27
|
super(client, { prefix: 'chainHead', supportedVersions: ['unstable', 'v1'], ...options });
|
|
27
28
|
this.#handlers = {};
|
|
@@ -32,6 +33,8 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
32
33
|
this.#retryQueue = new utils_1.AsyncQueue();
|
|
33
34
|
this.#blockUsage = new BlockUsage_js_1.BlockUsage();
|
|
34
35
|
this.#cache = new Map();
|
|
36
|
+
// This helps us to not accidentally putting too much stress on the JSON-RPC server, especially smoldot/light-client
|
|
37
|
+
this.#operationQueue = new utils_1.ThrottleQueue(this.#__unsafe__isSmoldot() ? 25 : 250);
|
|
35
38
|
}
|
|
36
39
|
async runtimeVersion() {
|
|
37
40
|
await this.#ensureFollowed();
|
|
@@ -236,7 +239,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
236
239
|
.then(() => {
|
|
237
240
|
// 3. Resolve the recovering promise
|
|
238
241
|
// This means to continue all pending requests while the chainHead started recovering mode at step 1.
|
|
239
|
-
this.#recovering
|
|
242
|
+
this.#recovering?.resolve();
|
|
240
243
|
// 4. Recover stale operations
|
|
241
244
|
// 4.1. Operations that's going on & waiting to receiving its operationId
|
|
242
245
|
// will eventually get an `limitedReached` error for using a stale followSubscriptionId
|
|
@@ -252,7 +255,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
252
255
|
.catch((e) => {
|
|
253
256
|
console.error(e);
|
|
254
257
|
// TODO we should retry a few attempts
|
|
255
|
-
this.#recovering
|
|
258
|
+
this.#recovering?.reject(new error_js_1.ChainHeadError('Cannot recover from stop event!'));
|
|
256
259
|
Object.values(this.#handlers).forEach(({ defer, operationId }) => {
|
|
257
260
|
defer.reject(new error_js_1.ChainHeadError('Cannot recover from stop event!'));
|
|
258
261
|
delete this.#handlers[operationId];
|
|
@@ -400,6 +403,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
400
403
|
this.#retryQueue.clear();
|
|
401
404
|
this.#blockUsage.clear();
|
|
402
405
|
this.#cache.clear();
|
|
406
|
+
this.#operationQueue.cancel();
|
|
403
407
|
}
|
|
404
408
|
async #ensureFollowed() {
|
|
405
409
|
if (this.#recovering) {
|
|
@@ -485,7 +489,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
485
489
|
const resp = await this.send('body', this.#subscriptionId, hash);
|
|
486
490
|
return this.#awaitOperation(resp, hash);
|
|
487
491
|
};
|
|
488
|
-
const resp = await this.#performOperationWithRetry(operation, atHash);
|
|
492
|
+
const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(operation, atHash));
|
|
489
493
|
this.#cache.set(cacheKey, resp);
|
|
490
494
|
return resp;
|
|
491
495
|
}
|
|
@@ -514,7 +518,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
514
518
|
const resp = await this.send('call', this.#subscriptionId, hash, func, params);
|
|
515
519
|
return this.#awaitOperation(resp, hash);
|
|
516
520
|
};
|
|
517
|
-
const resp = await this.#performOperationWithRetry(operation, atHash);
|
|
521
|
+
const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(operation, atHash));
|
|
518
522
|
this.#cache.set(cacheKey, resp);
|
|
519
523
|
return resp;
|
|
520
524
|
}
|
|
@@ -557,9 +561,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
557
561
|
}
|
|
558
562
|
this.#blockUsage.use(hash);
|
|
559
563
|
let results = [];
|
|
560
|
-
|
|
561
|
-
const isSmoldot = typeof this.client.provider['chain'] === 'function';
|
|
562
|
-
if (isSmoldot) {
|
|
564
|
+
if (this.#__unsafe__isSmoldot()) {
|
|
563
565
|
const fetchItem = async (item) => {
|
|
564
566
|
const [batch, newDiscardedItems] = await this.#getStorage([item], childTrie ?? null, hash);
|
|
565
567
|
if (newDiscardedItems.length > 0) {
|
|
@@ -592,7 +594,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
592
594
|
}
|
|
593
595
|
async #getStorage(items, childTrie, at) {
|
|
594
596
|
const operation = () => this.#getStorageOperation(items, childTrie, this.#ensurePinnedHash(at));
|
|
595
|
-
return this.#performOperationWithRetry(operation, at);
|
|
597
|
+
return this.#operationQueue.add(() => this.#performOperationWithRetry(operation, at));
|
|
596
598
|
}
|
|
597
599
|
async #getStorageOperation(items, childTrie, at) {
|
|
598
600
|
await this.#ensureFollowed();
|
|
@@ -629,5 +631,9 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
629
631
|
return;
|
|
630
632
|
await this.send('unpin', this.#subscriptionId, hashes);
|
|
631
633
|
}
|
|
634
|
+
#__unsafe__isSmoldot() {
|
|
635
|
+
// @ts-ignore a trick internally to check whether a provider is using smoldot connection
|
|
636
|
+
return typeof this.client.provider['chain'] === 'function';
|
|
637
|
+
}
|
|
632
638
|
}
|
|
633
639
|
exports.ChainHead = ChainHead;
|
|
@@ -83,7 +83,13 @@ class NewStorageQuery extends BaseStorageQuery_js_1.BaseStorageQuery {
|
|
|
83
83
|
await pull(best);
|
|
84
84
|
// Subscribe to best block events
|
|
85
85
|
const unsub = this.client.on('bestBlock', (block) => {
|
|
86
|
-
|
|
86
|
+
// Here we're handling each pull one by one,
|
|
87
|
+
// If the queue get too long, it might take a long time for us to get the fresh & latest data
|
|
88
|
+
// This is a precaution in such case, if the queue size >= 3 we skip all the pending pull and jump to the latest pull
|
|
89
|
+
if (pullQueue.size >= 3)
|
|
90
|
+
pullQueue.clear();
|
|
91
|
+
// TODO timing out for a pull to prevent it took too long to fetch
|
|
92
|
+
pullQueue.enqueue(() => pull(block)).catch(utils_1.noop);
|
|
87
93
|
});
|
|
88
94
|
return async () => {
|
|
89
95
|
unsub();
|
package/executor/Executor.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as $ from '@dedot/shape';
|
|
2
2
|
import { ensurePresence, u8aToHex } from '@dedot/utils';
|
|
3
|
-
import { SignedExtension } from './SignedExtension.js';
|
|
4
3
|
import { FallbackSignedExtension, isEmptyStructOrTuple } from './FallbackSignedExtension.js';
|
|
4
|
+
import { SignedExtension } from './SignedExtension.js';
|
|
5
5
|
import { knownSignedExtensions } from './known/index.js';
|
|
6
6
|
export class ExtraSignedExtension extends SignedExtension {
|
|
7
7
|
#signedExtensions;
|
|
@@ -57,13 +57,20 @@ export class ExtraSignedExtension extends SignedExtension {
|
|
|
57
57
|
* @returns boolean
|
|
58
58
|
*/
|
|
59
59
|
isRequireNoExternalInputs(extDef) {
|
|
60
|
-
return (isEmptyStructOrTuple(this.registry, extDef.typeId) &&
|
|
60
|
+
return (isEmptyStructOrTuple(this.registry, extDef.typeId) && // prettier-end-here
|
|
61
61
|
isEmptyStructOrTuple(this.registry, extDef.additionalSigned));
|
|
62
62
|
}
|
|
63
63
|
toPayload(call = '0x') {
|
|
64
64
|
const signedExtensions = this.#signedExtensions.map((se) => se.identifier);
|
|
65
65
|
const { version } = this.registry.metadata.extrinsic;
|
|
66
|
-
|
|
66
|
+
const { signerAddress } = this.options;
|
|
67
|
+
return Object.assign({
|
|
68
|
+
address: signerAddress,
|
|
69
|
+
signedExtensions,
|
|
70
|
+
version,
|
|
71
|
+
method: call,
|
|
72
|
+
withSignedTransaction: true, // allow signer/wallet to alter transaction by default
|
|
73
|
+
}, ...this.#signedExtensions.map((se) => se.toPayload()));
|
|
67
74
|
}
|
|
68
75
|
toRawPayload(call = '0x') {
|
|
69
76
|
const payload = this.toPayload(call);
|
|
@@ -88,10 +88,6 @@ export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
|
88
88
|
if (!alteredTx.signed) {
|
|
89
89
|
throw new DedotError('Altered transaction from signer is not signed');
|
|
90
90
|
}
|
|
91
|
-
// Signer's not allow the change the call data
|
|
92
|
-
if (alteredTx.callHex !== this.callHex) {
|
|
93
|
-
throw new DedotError('Call data does not match, signer is not allowed to change tx call data.');
|
|
94
|
-
}
|
|
95
91
|
}
|
|
96
92
|
#getSigner(options) {
|
|
97
93
|
return options?.signer || this.client.options.signer;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $Header } from '@dedot/codecs';
|
|
2
|
-
import { assert, AsyncQueue, deferred, ensurePresence, noop, waitFor } from '@dedot/utils';
|
|
2
|
+
import { assert, AsyncQueue, deferred, ensurePresence, noop, ThrottleQueue, waitFor, } from '@dedot/utils';
|
|
3
3
|
import { JsonRpcGroup } from '../JsonRpcGroup.js';
|
|
4
4
|
import { BlockUsage } from './BlockUsage.js';
|
|
5
5
|
import { ChainHeadBlockNotPinnedError, ChainHeadBlockPrunedError, ChainHeadError, ChainHeadLimitReachedError, ChainHeadOperationError, ChainHeadOperationInaccessibleError, ChainHeadStopError, RetryStrategy, } from './error.js';
|
|
@@ -19,6 +19,7 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
19
19
|
#recovering;
|
|
20
20
|
#blockUsage;
|
|
21
21
|
#cache;
|
|
22
|
+
#operationQueue;
|
|
22
23
|
constructor(client, options) {
|
|
23
24
|
super(client, { prefix: 'chainHead', supportedVersions: ['unstable', 'v1'], ...options });
|
|
24
25
|
this.#handlers = {};
|
|
@@ -29,6 +30,8 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
29
30
|
this.#retryQueue = new AsyncQueue();
|
|
30
31
|
this.#blockUsage = new BlockUsage();
|
|
31
32
|
this.#cache = new Map();
|
|
33
|
+
// This helps us to not accidentally putting too much stress on the JSON-RPC server, especially smoldot/light-client
|
|
34
|
+
this.#operationQueue = new ThrottleQueue(this.#__unsafe__isSmoldot() ? 25 : 250);
|
|
32
35
|
}
|
|
33
36
|
async runtimeVersion() {
|
|
34
37
|
await this.#ensureFollowed();
|
|
@@ -233,7 +236,7 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
233
236
|
.then(() => {
|
|
234
237
|
// 3. Resolve the recovering promise
|
|
235
238
|
// This means to continue all pending requests while the chainHead started recovering mode at step 1.
|
|
236
|
-
this.#recovering
|
|
239
|
+
this.#recovering?.resolve();
|
|
237
240
|
// 4. Recover stale operations
|
|
238
241
|
// 4.1. Operations that's going on & waiting to receiving its operationId
|
|
239
242
|
// will eventually get an `limitedReached` error for using a stale followSubscriptionId
|
|
@@ -249,7 +252,7 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
249
252
|
.catch((e) => {
|
|
250
253
|
console.error(e);
|
|
251
254
|
// TODO we should retry a few attempts
|
|
252
|
-
this.#recovering
|
|
255
|
+
this.#recovering?.reject(new ChainHeadError('Cannot recover from stop event!'));
|
|
253
256
|
Object.values(this.#handlers).forEach(({ defer, operationId }) => {
|
|
254
257
|
defer.reject(new ChainHeadError('Cannot recover from stop event!'));
|
|
255
258
|
delete this.#handlers[operationId];
|
|
@@ -397,6 +400,7 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
397
400
|
this.#retryQueue.clear();
|
|
398
401
|
this.#blockUsage.clear();
|
|
399
402
|
this.#cache.clear();
|
|
403
|
+
this.#operationQueue.cancel();
|
|
400
404
|
}
|
|
401
405
|
async #ensureFollowed() {
|
|
402
406
|
if (this.#recovering) {
|
|
@@ -482,7 +486,7 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
482
486
|
const resp = await this.send('body', this.#subscriptionId, hash);
|
|
483
487
|
return this.#awaitOperation(resp, hash);
|
|
484
488
|
};
|
|
485
|
-
const resp = await this.#performOperationWithRetry(operation, atHash);
|
|
489
|
+
const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(operation, atHash));
|
|
486
490
|
this.#cache.set(cacheKey, resp);
|
|
487
491
|
return resp;
|
|
488
492
|
}
|
|
@@ -511,7 +515,7 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
511
515
|
const resp = await this.send('call', this.#subscriptionId, hash, func, params);
|
|
512
516
|
return this.#awaitOperation(resp, hash);
|
|
513
517
|
};
|
|
514
|
-
const resp = await this.#performOperationWithRetry(operation, atHash);
|
|
518
|
+
const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(operation, atHash));
|
|
515
519
|
this.#cache.set(cacheKey, resp);
|
|
516
520
|
return resp;
|
|
517
521
|
}
|
|
@@ -554,9 +558,7 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
554
558
|
}
|
|
555
559
|
this.#blockUsage.use(hash);
|
|
556
560
|
let results = [];
|
|
557
|
-
|
|
558
|
-
const isSmoldot = typeof this.client.provider['chain'] === 'function';
|
|
559
|
-
if (isSmoldot) {
|
|
561
|
+
if (this.#__unsafe__isSmoldot()) {
|
|
560
562
|
const fetchItem = async (item) => {
|
|
561
563
|
const [batch, newDiscardedItems] = await this.#getStorage([item], childTrie ?? null, hash);
|
|
562
564
|
if (newDiscardedItems.length > 0) {
|
|
@@ -589,7 +591,7 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
589
591
|
}
|
|
590
592
|
async #getStorage(items, childTrie, at) {
|
|
591
593
|
const operation = () => this.#getStorageOperation(items, childTrie, this.#ensurePinnedHash(at));
|
|
592
|
-
return this.#performOperationWithRetry(operation, at);
|
|
594
|
+
return this.#operationQueue.add(() => this.#performOperationWithRetry(operation, at));
|
|
593
595
|
}
|
|
594
596
|
async #getStorageOperation(items, childTrie, at) {
|
|
595
597
|
await this.#ensureFollowed();
|
|
@@ -626,4 +628,8 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
626
628
|
return;
|
|
627
629
|
await this.send('unpin', this.#subscriptionId, hashes);
|
|
628
630
|
}
|
|
631
|
+
#__unsafe__isSmoldot() {
|
|
632
|
+
// @ts-ignore a trick internally to check whether a provider is using smoldot connection
|
|
633
|
+
return typeof this.client.provider['chain'] === 'function';
|
|
634
|
+
}
|
|
629
635
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dedot/api",
|
|
3
|
-
"version": "0.9.5-next.
|
|
3
|
+
"version": "0.9.5-next.4fd5def5.41+4fd5def5",
|
|
4
4
|
"description": "A delightful JavaScript/TypeScript client for Polkadot & Substrate",
|
|
5
5
|
"author": "Thang X. Vu <thang@dedot.dev>",
|
|
6
6
|
"homepage": "https://dedot.dev",
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
"type": "module",
|
|
14
14
|
"sideEffects": false,
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@dedot/codecs": "0.9.5-next.
|
|
17
|
-
"@dedot/providers": "0.9.5-next.
|
|
18
|
-
"@dedot/runtime-specs": "0.9.5-next.
|
|
19
|
-
"@dedot/shape": "0.9.5-next.
|
|
20
|
-
"@dedot/storage": "0.9.5-next.
|
|
21
|
-
"@dedot/types": "0.9.5-next.
|
|
22
|
-
"@dedot/utils": "0.9.5-next.
|
|
16
|
+
"@dedot/codecs": "0.9.5-next.4fd5def5.41+4fd5def5",
|
|
17
|
+
"@dedot/providers": "0.9.5-next.4fd5def5.41+4fd5def5",
|
|
18
|
+
"@dedot/runtime-specs": "0.9.5-next.4fd5def5.41+4fd5def5",
|
|
19
|
+
"@dedot/shape": "0.9.5-next.4fd5def5.41+4fd5def5",
|
|
20
|
+
"@dedot/storage": "0.9.5-next.4fd5def5.41+4fd5def5",
|
|
21
|
+
"@dedot/types": "0.9.5-next.4fd5def5.41+4fd5def5",
|
|
22
|
+
"@dedot/utils": "0.9.5-next.4fd5def5.41+4fd5def5"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"node": ">=18"
|
|
49
49
|
},
|
|
50
50
|
"license": "Apache-2.0",
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "4fd5def58b4308a9c05483e226a6a43ff6405667",
|
|
52
52
|
"module": "./index.js",
|
|
53
53
|
"types": "./index.d.ts"
|
|
54
54
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AsyncQueue } from '@dedot/utils';
|
|
1
|
+
import { AsyncQueue, noop } from '@dedot/utils';
|
|
2
2
|
import { BaseStorageQuery } from './BaseStorageQuery.js';
|
|
3
3
|
/**
|
|
4
4
|
* @name NewStorageQuery
|
|
@@ -80,7 +80,13 @@ export class NewStorageQuery extends BaseStorageQuery {
|
|
|
80
80
|
await pull(best);
|
|
81
81
|
// Subscribe to best block events
|
|
82
82
|
const unsub = this.client.on('bestBlock', (block) => {
|
|
83
|
-
|
|
83
|
+
// Here we're handling each pull one by one,
|
|
84
|
+
// If the queue get too long, it might take a long time for us to get the fresh & latest data
|
|
85
|
+
// This is a precaution in such case, if the queue size >= 3 we skip all the pending pull and jump to the latest pull
|
|
86
|
+
if (pullQueue.size >= 3)
|
|
87
|
+
pullQueue.clear();
|
|
88
|
+
// TODO timing out for a pull to prevent it took too long to fetch
|
|
89
|
+
pullQueue.enqueue(() => pull(block)).catch(noop);
|
|
84
90
|
});
|
|
85
91
|
return async () => {
|
|
86
92
|
unsub();
|