@dedot/api 0.18.5 → 0.18.6

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.
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ChainHead = exports.MIN_FINALIZED_QUEUE_SIZE = void 0;
3
+ exports.ChainHead = void 0;
4
4
  const codecs_1 = require("@dedot/codecs");
5
5
  const utils_1 = require("@dedot/utils");
6
6
  const JsonRpcGroup_js_1 = require("../JsonRpcGroup.js");
7
7
  const BlockUsage_js_1 = require("./BlockUsage.js");
8
8
  const error_js_1 = require("./error.js");
9
- exports.MIN_FINALIZED_QUEUE_SIZE = 10; // finalized queue size
9
+ const MIN_FINALIZED_QUEUE_SIZE = 16; // finalized queue size
10
10
  const CHAINHEAD_CACHE_CAPACITY = 256;
11
11
  const CHAINHEAD_CACHE_TTL = 30_000; // 30 seconds
12
12
  class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
@@ -25,6 +25,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
25
25
  #blockUsage;
26
26
  #cache;
27
27
  #operationQueue;
28
+ #minQueueSize;
28
29
  /**
29
30
  * Archive instance used as fallback when ChainHead blocks are not pinned.
30
31
  *
@@ -48,6 +49,7 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
48
49
  this.#cache = new utils_1.LRUCache(CHAINHEAD_CACHE_CAPACITY, CHAINHEAD_CACHE_TTL);
49
50
  // This helps us to not accidentally putting too much stress on the JSON-RPC server, especially smoldot/light-client
50
51
  this.#operationQueue = new utils_1.ThrottleQueue(this.#__unsafe__isSmoldot() ? 25 : 250);
52
+ this.#minQueueSize = MIN_FINALIZED_QUEUE_SIZE;
51
53
  }
52
54
  /**
53
55
  * Attach an Archive instance as fallback for operations that fail due to unpinned blocks.
@@ -140,6 +142,9 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
140
142
  finalizedBlockHashes.push(finalizedBlockHash);
141
143
  this.#subscriptionId = subscription.subscriptionId;
142
144
  this.#finalizedQueue = finalizedBlockHashes;
145
+ if (finalizedBlockHashes.length > MIN_FINALIZED_QUEUE_SIZE) {
146
+ this.#minQueueSize = finalizedBlockHashes.length;
147
+ }
143
148
  this.#finalizedRuntime = this.#extractRuntime(finalizedBlockRuntime);
144
149
  (0, utils_1.assert)(this.#finalizedRuntime, 'Invalid finalized runtime');
145
150
  this.#bestHash = this.#finalizedHash = finalizedBlockHashes.at(-1);
@@ -224,9 +229,9 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
224
229
  const pinnedHashes = Object.keys(this.#pinnedBlocks);
225
230
  const hashesToUnpin = new Set(prunedBlockHashes.filter((hash) => pinnedHashes.includes(hash)));
226
231
  // Unpin the oldest finalized pinned blocks to maintain the queue size
227
- if (this.#finalizedQueue.length > exports.MIN_FINALIZED_QUEUE_SIZE) {
232
+ if (this.#finalizedQueue.length > this.#minQueueSize) {
228
233
  const finalizedQueue = this.#finalizedQueue.slice();
229
- const numOfItemsToUnpin = finalizedQueue.length - exports.MIN_FINALIZED_QUEUE_SIZE;
234
+ const numOfItemsToUnpin = finalizedQueue.length - this.#minQueueSize;
230
235
  const queuedHashesToUnpin = finalizedQueue.splice(0, numOfItemsToUnpin);
231
236
  queuedHashesToUnpin.forEach((hash) => {
232
237
  // if the block is being used, we'll keep it pinned
@@ -553,9 +558,15 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
553
558
  const resp = await this.send('body', this.#subscriptionId, hash);
554
559
  return this.#awaitOperation(resp, hash);
555
560
  };
556
- const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(bodyOperation, atHash));
557
- this.#cache.set(cacheKey, resp);
558
- return resp;
561
+ try {
562
+ this.#blockUsage.use(atHash);
563
+ const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(bodyOperation, atHash));
564
+ this.#cache.set(cacheKey, resp);
565
+ return resp;
566
+ }
567
+ finally {
568
+ this.#blockUsage.release(atHash);
569
+ }
559
570
  };
560
571
  const fallback = async (archive, hash) => {
561
572
  const result = await archive.body(hash);
@@ -593,9 +604,15 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
593
604
  const resp = await this.send('call', this.#subscriptionId, hash, func, params);
594
605
  return this.#awaitOperation(resp, hash);
595
606
  };
596
- const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(callOperation, atHash));
597
- this.#cache.set(cacheKey, resp);
598
- return resp;
607
+ try {
608
+ this.#blockUsage.use(atHash);
609
+ const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(callOperation, atHash));
610
+ this.#cache.set(cacheKey, resp);
611
+ return resp;
612
+ }
613
+ finally {
614
+ this.#blockUsage.release(atHash);
615
+ }
599
616
  };
600
617
  const fallback = (archive, hash) => archive.call(func, params, hash);
601
618
  try {
@@ -687,7 +704,13 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
687
704
  }
688
705
  async #getStorage(items, childTrie, at) {
689
706
  const operation = () => this.#getStorageOperation(items, childTrie, this.#ensurePinnedHash(at));
690
- return this.#operationQueue.add(() => this.#performOperationWithRetry(operation, at));
707
+ try {
708
+ this.#blockUsage.use(at);
709
+ return await this.#operationQueue.add(() => this.#performOperationWithRetry(operation, at));
710
+ }
711
+ finally {
712
+ this.#blockUsage.release(at);
713
+ }
691
714
  }
692
715
  async #getStorageOperation(items, childTrie, at) {
693
716
  await this.#ensureFollowed();
@@ -17,7 +17,6 @@ export type PinnedBlock = {
17
17
  runtime?: ChainHeadRuntimeVersion;
18
18
  };
19
19
  export type ChainHeadEvent = 'newBlock' | 'bestBlock' | 'finalizedBlock' | 'bestChainChanged';
20
- export declare const MIN_FINALIZED_QUEUE_SIZE = 10;
21
20
  export declare class ChainHead extends JsonRpcGroup<ChainHeadEvent> {
22
21
  #private;
23
22
  constructor(client: IJsonRpcClient, options?: Partial<JsonRpcGroupOptions>);
@@ -3,7 +3,7 @@ import { assert, AsyncQueue, deferred, ensurePresence, noop, ThrottleQueue, wait
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';
6
- export const MIN_FINALIZED_QUEUE_SIZE = 10; // finalized queue size
6
+ const MIN_FINALIZED_QUEUE_SIZE = 16; // finalized queue size
7
7
  const CHAINHEAD_CACHE_CAPACITY = 256;
8
8
  const CHAINHEAD_CACHE_TTL = 30_000; // 30 seconds
9
9
  export class ChainHead extends JsonRpcGroup {
@@ -22,6 +22,7 @@ export class ChainHead extends JsonRpcGroup {
22
22
  #blockUsage;
23
23
  #cache;
24
24
  #operationQueue;
25
+ #minQueueSize;
25
26
  /**
26
27
  * Archive instance used as fallback when ChainHead blocks are not pinned.
27
28
  *
@@ -45,6 +46,7 @@ export class ChainHead extends JsonRpcGroup {
45
46
  this.#cache = new LRUCache(CHAINHEAD_CACHE_CAPACITY, CHAINHEAD_CACHE_TTL);
46
47
  // This helps us to not accidentally putting too much stress on the JSON-RPC server, especially smoldot/light-client
47
48
  this.#operationQueue = new ThrottleQueue(this.#__unsafe__isSmoldot() ? 25 : 250);
49
+ this.#minQueueSize = MIN_FINALIZED_QUEUE_SIZE;
48
50
  }
49
51
  /**
50
52
  * Attach an Archive instance as fallback for operations that fail due to unpinned blocks.
@@ -137,6 +139,9 @@ export class ChainHead extends JsonRpcGroup {
137
139
  finalizedBlockHashes.push(finalizedBlockHash);
138
140
  this.#subscriptionId = subscription.subscriptionId;
139
141
  this.#finalizedQueue = finalizedBlockHashes;
142
+ if (finalizedBlockHashes.length > MIN_FINALIZED_QUEUE_SIZE) {
143
+ this.#minQueueSize = finalizedBlockHashes.length;
144
+ }
140
145
  this.#finalizedRuntime = this.#extractRuntime(finalizedBlockRuntime);
141
146
  assert(this.#finalizedRuntime, 'Invalid finalized runtime');
142
147
  this.#bestHash = this.#finalizedHash = finalizedBlockHashes.at(-1);
@@ -221,9 +226,9 @@ export class ChainHead extends JsonRpcGroup {
221
226
  const pinnedHashes = Object.keys(this.#pinnedBlocks);
222
227
  const hashesToUnpin = new Set(prunedBlockHashes.filter((hash) => pinnedHashes.includes(hash)));
223
228
  // Unpin the oldest finalized pinned blocks to maintain the queue size
224
- if (this.#finalizedQueue.length > MIN_FINALIZED_QUEUE_SIZE) {
229
+ if (this.#finalizedQueue.length > this.#minQueueSize) {
225
230
  const finalizedQueue = this.#finalizedQueue.slice();
226
- const numOfItemsToUnpin = finalizedQueue.length - MIN_FINALIZED_QUEUE_SIZE;
231
+ const numOfItemsToUnpin = finalizedQueue.length - this.#minQueueSize;
227
232
  const queuedHashesToUnpin = finalizedQueue.splice(0, numOfItemsToUnpin);
228
233
  queuedHashesToUnpin.forEach((hash) => {
229
234
  // if the block is being used, we'll keep it pinned
@@ -550,9 +555,15 @@ export class ChainHead extends JsonRpcGroup {
550
555
  const resp = await this.send('body', this.#subscriptionId, hash);
551
556
  return this.#awaitOperation(resp, hash);
552
557
  };
553
- const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(bodyOperation, atHash));
554
- this.#cache.set(cacheKey, resp);
555
- return resp;
558
+ try {
559
+ this.#blockUsage.use(atHash);
560
+ const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(bodyOperation, atHash));
561
+ this.#cache.set(cacheKey, resp);
562
+ return resp;
563
+ }
564
+ finally {
565
+ this.#blockUsage.release(atHash);
566
+ }
556
567
  };
557
568
  const fallback = async (archive, hash) => {
558
569
  const result = await archive.body(hash);
@@ -590,9 +601,15 @@ export class ChainHead extends JsonRpcGroup {
590
601
  const resp = await this.send('call', this.#subscriptionId, hash, func, params);
591
602
  return this.#awaitOperation(resp, hash);
592
603
  };
593
- const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(callOperation, atHash));
594
- this.#cache.set(cacheKey, resp);
595
- return resp;
604
+ try {
605
+ this.#blockUsage.use(atHash);
606
+ const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(callOperation, atHash));
607
+ this.#cache.set(cacheKey, resp);
608
+ return resp;
609
+ }
610
+ finally {
611
+ this.#blockUsage.release(atHash);
612
+ }
596
613
  };
597
614
  const fallback = (archive, hash) => archive.call(func, params, hash);
598
615
  try {
@@ -684,7 +701,13 @@ export class ChainHead extends JsonRpcGroup {
684
701
  }
685
702
  async #getStorage(items, childTrie, at) {
686
703
  const operation = () => this.#getStorageOperation(items, childTrie, this.#ensurePinnedHash(at));
687
- return this.#operationQueue.add(() => this.#performOperationWithRetry(operation, at));
704
+ try {
705
+ this.#blockUsage.use(at);
706
+ return await this.#operationQueue.add(() => this.#performOperationWithRetry(operation, at));
707
+ }
708
+ finally {
709
+ this.#blockUsage.release(at);
710
+ }
688
711
  }
689
712
  async #getStorageOperation(items, childTrie, at) {
690
713
  await this.#ensureFollowed();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dedot/api",
3
- "version": "0.18.5",
3
+ "version": "0.18.6",
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.18.5",
17
- "@dedot/providers": "0.18.5",
18
- "@dedot/runtime-specs": "0.18.5",
19
- "@dedot/shape": "0.18.5",
20
- "@dedot/storage": "0.18.5",
21
- "@dedot/types": "0.18.5",
22
- "@dedot/utils": "0.18.5"
16
+ "@dedot/codecs": "0.18.6",
17
+ "@dedot/providers": "0.18.6",
18
+ "@dedot/runtime-specs": "0.18.6",
19
+ "@dedot/shape": "0.18.6",
20
+ "@dedot/storage": "0.18.6",
21
+ "@dedot/types": "0.18.6",
22
+ "@dedot/utils": "0.18.6"
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": "54b0dcfddfc775009eacd1858441b1b2b12b9cae",
51
+ "gitHead": "2ff0200696aa2e42505d30369fe84b2416838791",
52
52
  "module": "./index.js",
53
53
  "types": "./index.d.ts"
54
54
  }