@dedot/api 0.9.3 → 0.9.5-next.11b0ca8e.3
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.
|
@@ -80,11 +80,18 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
80
80
|
const defer = (0, utils_1.deferred)();
|
|
81
81
|
try {
|
|
82
82
|
this.#unsub && this.#unsub().catch(utils_1.noop); // ensure unfollowed
|
|
83
|
+
let signals = 0;
|
|
83
84
|
this.#unsub = await this.send('follow', true, (event, subscription) => {
|
|
84
85
|
this.#followResponseQueue
|
|
85
86
|
.enqueue(async () => {
|
|
86
87
|
await this.#onFollowEvent(event, subscription);
|
|
87
|
-
if (
|
|
88
|
+
if (signals >= 2)
|
|
89
|
+
return;
|
|
90
|
+
signals += 1;
|
|
91
|
+
// Sometime smoldot send a `stop` event right after `initialized`
|
|
92
|
+
// So requests sending between `initialized` and `stop` will be on pruned hashes -> throwing out errors
|
|
93
|
+
// Here we make sure to receive at least the first 2 signals to resolve
|
|
94
|
+
if (signals >= 2) {
|
|
88
95
|
defer.resolve();
|
|
89
96
|
}
|
|
90
97
|
})
|
|
@@ -167,28 +174,18 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
167
174
|
return;
|
|
168
175
|
this.#finalizedQueue.push(hash);
|
|
169
176
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
// that's probably a premature optimization
|
|
173
|
-
const finalizedBlockHeights = finalizedBlockHashes.map((hash) => this.findBlock(hash).number);
|
|
174
|
-
const pinnedHashes = Object.keys(this.#pinnedBlocks);
|
|
175
|
-
const hashesToUnpin = new Set([
|
|
176
|
-
...prunedBlockHashes.filter((hash) => pinnedHashes.includes(hash)),
|
|
177
|
-
// Since we have the current finalized blocks,
|
|
178
|
-
// we can mark all the other blocks at the same height as pruned and unpin all together with the reported pruned blocks
|
|
179
|
-
...Object.values(this.#pinnedBlocks)
|
|
180
|
-
.filter((b) => finalizedBlockHeights.includes(b.number))
|
|
181
|
-
.filter((b) => !finalizedBlockHashes.includes(b.hash))
|
|
182
|
-
.map((b) => b.hash),
|
|
183
|
-
]);
|
|
177
|
+
const currentFinalizedBlock = this.findBlock(this.#finalizedHash);
|
|
178
|
+
this.emit('finalizedBlock', currentFinalizedBlock);
|
|
184
179
|
// TODO account for operations that haven't received its operationId yet
|
|
185
180
|
Object.values(this.#handlers).forEach(({ defer, hash, operationId }) => {
|
|
186
|
-
if (
|
|
181
|
+
if (prunedBlockHashes.includes(hash)) {
|
|
187
182
|
defer.reject(new error_js_1.ChainHeadBlockPrunedError());
|
|
188
183
|
this.stopOperation(operationId).catch(utils_1.noop);
|
|
189
184
|
delete this.#handlers[operationId];
|
|
190
185
|
}
|
|
191
186
|
});
|
|
187
|
+
const pinnedHashes = Object.keys(this.#pinnedBlocks);
|
|
188
|
+
const hashesToUnpin = new Set(prunedBlockHashes.filter((hash) => pinnedHashes.includes(hash)));
|
|
192
189
|
// Unpin the oldest finalized pinned blocks to maintain the queue size
|
|
193
190
|
if (this.#finalizedQueue.length > exports.MIN_FINALIZED_QUEUE_SIZE) {
|
|
194
191
|
const finalizedQueue = this.#finalizedQueue.slice();
|
|
@@ -206,6 +203,17 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
206
203
|
});
|
|
207
204
|
this.#finalizedQueue = finalizedQueue;
|
|
208
205
|
}
|
|
206
|
+
// Unpin all obsolete blocks with blockNumber < the latest finalized block number
|
|
207
|
+
// & not a finalized block & is not in use
|
|
208
|
+
pinnedHashes.forEach((hash) => {
|
|
209
|
+
if (this.#blockUsage.usage(hash) > 0)
|
|
210
|
+
return;
|
|
211
|
+
if (this.#finalizedQueue.includes(hash))
|
|
212
|
+
return;
|
|
213
|
+
if (this.findBlock(hash).number > currentFinalizedBlock.number)
|
|
214
|
+
return;
|
|
215
|
+
hashesToUnpin.add(hash);
|
|
216
|
+
});
|
|
209
217
|
hashesToUnpin.forEach((hash) => {
|
|
210
218
|
if (!this.isPinned(hash))
|
|
211
219
|
return;
|
|
@@ -421,17 +429,15 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
421
429
|
async #retryOperation(strategy, retry) {
|
|
422
430
|
try {
|
|
423
431
|
return await new Promise((resolve, reject) => {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
}); // retry again in the next tick
|
|
432
|
+
if (strategy === error_js_1.RetryStrategy.NOW) {
|
|
433
|
+
retry().then(resolve).catch(reject);
|
|
434
|
+
}
|
|
435
|
+
else if (strategy === error_js_1.RetryStrategy.QUEUED) {
|
|
436
|
+
this.#retryQueue.enqueue(retry).then(resolve).catch(reject);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
throw new Error('Invalid retry strategy');
|
|
440
|
+
}
|
|
435
441
|
});
|
|
436
442
|
}
|
|
437
443
|
catch (e) {
|
|
@@ -555,16 +561,13 @@ class ChainHead extends JsonRpcGroup_js_1.JsonRpcGroup {
|
|
|
555
561
|
const isSmoldot = typeof this.client.provider['chain'] === 'function';
|
|
556
562
|
if (isSmoldot) {
|
|
557
563
|
const fetchItem = async (item) => {
|
|
558
|
-
const [
|
|
564
|
+
const [batch, newDiscardedItems] = await this.#getStorage([item], childTrie ?? null, hash);
|
|
559
565
|
if (newDiscardedItems.length > 0) {
|
|
560
566
|
return fetchItem(item);
|
|
561
567
|
}
|
|
562
|
-
|
|
563
|
-
return { key: item.key, value: undefined };
|
|
564
|
-
}
|
|
565
|
-
return newBatch[0];
|
|
568
|
+
return batch;
|
|
566
569
|
};
|
|
567
|
-
results = await Promise.all(items.map((one) => fetchItem(one)));
|
|
570
|
+
results = (await Promise.all(items.map((one) => fetchItem(one)))).flat();
|
|
568
571
|
}
|
|
569
572
|
else {
|
|
570
573
|
let queryItems = items;
|
|
@@ -77,11 +77,18 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
77
77
|
const defer = deferred();
|
|
78
78
|
try {
|
|
79
79
|
this.#unsub && this.#unsub().catch(noop); // ensure unfollowed
|
|
80
|
+
let signals = 0;
|
|
80
81
|
this.#unsub = await this.send('follow', true, (event, subscription) => {
|
|
81
82
|
this.#followResponseQueue
|
|
82
83
|
.enqueue(async () => {
|
|
83
84
|
await this.#onFollowEvent(event, subscription);
|
|
84
|
-
if (
|
|
85
|
+
if (signals >= 2)
|
|
86
|
+
return;
|
|
87
|
+
signals += 1;
|
|
88
|
+
// Sometime smoldot send a `stop` event right after `initialized`
|
|
89
|
+
// So requests sending between `initialized` and `stop` will be on pruned hashes -> throwing out errors
|
|
90
|
+
// Here we make sure to receive at least the first 2 signals to resolve
|
|
91
|
+
if (signals >= 2) {
|
|
85
92
|
defer.resolve();
|
|
86
93
|
}
|
|
87
94
|
})
|
|
@@ -164,28 +171,18 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
164
171
|
return;
|
|
165
172
|
this.#finalizedQueue.push(hash);
|
|
166
173
|
});
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
// that's probably a premature optimization
|
|
170
|
-
const finalizedBlockHeights = finalizedBlockHashes.map((hash) => this.findBlock(hash).number);
|
|
171
|
-
const pinnedHashes = Object.keys(this.#pinnedBlocks);
|
|
172
|
-
const hashesToUnpin = new Set([
|
|
173
|
-
...prunedBlockHashes.filter((hash) => pinnedHashes.includes(hash)),
|
|
174
|
-
// Since we have the current finalized blocks,
|
|
175
|
-
// we can mark all the other blocks at the same height as pruned and unpin all together with the reported pruned blocks
|
|
176
|
-
...Object.values(this.#pinnedBlocks)
|
|
177
|
-
.filter((b) => finalizedBlockHeights.includes(b.number))
|
|
178
|
-
.filter((b) => !finalizedBlockHashes.includes(b.hash))
|
|
179
|
-
.map((b) => b.hash),
|
|
180
|
-
]);
|
|
174
|
+
const currentFinalizedBlock = this.findBlock(this.#finalizedHash);
|
|
175
|
+
this.emit('finalizedBlock', currentFinalizedBlock);
|
|
181
176
|
// TODO account for operations that haven't received its operationId yet
|
|
182
177
|
Object.values(this.#handlers).forEach(({ defer, hash, operationId }) => {
|
|
183
|
-
if (
|
|
178
|
+
if (prunedBlockHashes.includes(hash)) {
|
|
184
179
|
defer.reject(new ChainHeadBlockPrunedError());
|
|
185
180
|
this.stopOperation(operationId).catch(noop);
|
|
186
181
|
delete this.#handlers[operationId];
|
|
187
182
|
}
|
|
188
183
|
});
|
|
184
|
+
const pinnedHashes = Object.keys(this.#pinnedBlocks);
|
|
185
|
+
const hashesToUnpin = new Set(prunedBlockHashes.filter((hash) => pinnedHashes.includes(hash)));
|
|
189
186
|
// Unpin the oldest finalized pinned blocks to maintain the queue size
|
|
190
187
|
if (this.#finalizedQueue.length > MIN_FINALIZED_QUEUE_SIZE) {
|
|
191
188
|
const finalizedQueue = this.#finalizedQueue.slice();
|
|
@@ -203,6 +200,17 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
203
200
|
});
|
|
204
201
|
this.#finalizedQueue = finalizedQueue;
|
|
205
202
|
}
|
|
203
|
+
// Unpin all obsolete blocks with blockNumber < the latest finalized block number
|
|
204
|
+
// & not a finalized block & is not in use
|
|
205
|
+
pinnedHashes.forEach((hash) => {
|
|
206
|
+
if (this.#blockUsage.usage(hash) > 0)
|
|
207
|
+
return;
|
|
208
|
+
if (this.#finalizedQueue.includes(hash))
|
|
209
|
+
return;
|
|
210
|
+
if (this.findBlock(hash).number > currentFinalizedBlock.number)
|
|
211
|
+
return;
|
|
212
|
+
hashesToUnpin.add(hash);
|
|
213
|
+
});
|
|
206
214
|
hashesToUnpin.forEach((hash) => {
|
|
207
215
|
if (!this.isPinned(hash))
|
|
208
216
|
return;
|
|
@@ -418,17 +426,15 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
418
426
|
async #retryOperation(strategy, retry) {
|
|
419
427
|
try {
|
|
420
428
|
return await new Promise((resolve, reject) => {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
}); // retry again in the next tick
|
|
429
|
+
if (strategy === RetryStrategy.NOW) {
|
|
430
|
+
retry().then(resolve).catch(reject);
|
|
431
|
+
}
|
|
432
|
+
else if (strategy === RetryStrategy.QUEUED) {
|
|
433
|
+
this.#retryQueue.enqueue(retry).then(resolve).catch(reject);
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
throw new Error('Invalid retry strategy');
|
|
437
|
+
}
|
|
432
438
|
});
|
|
433
439
|
}
|
|
434
440
|
catch (e) {
|
|
@@ -552,16 +558,13 @@ export class ChainHead extends JsonRpcGroup {
|
|
|
552
558
|
const isSmoldot = typeof this.client.provider['chain'] === 'function';
|
|
553
559
|
if (isSmoldot) {
|
|
554
560
|
const fetchItem = async (item) => {
|
|
555
|
-
const [
|
|
561
|
+
const [batch, newDiscardedItems] = await this.#getStorage([item], childTrie ?? null, hash);
|
|
556
562
|
if (newDiscardedItems.length > 0) {
|
|
557
563
|
return fetchItem(item);
|
|
558
564
|
}
|
|
559
|
-
|
|
560
|
-
return { key: item.key, value: undefined };
|
|
561
|
-
}
|
|
562
|
-
return newBatch[0];
|
|
565
|
+
return batch;
|
|
563
566
|
};
|
|
564
|
-
results = await Promise.all(items.map((one) => fetchItem(one)));
|
|
567
|
+
results = (await Promise.all(items.map((one) => fetchItem(one)))).flat();
|
|
565
568
|
}
|
|
566
569
|
else {
|
|
567
570
|
let queryItems = items;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dedot/api",
|
|
3
|
-
"version": "0.9.3",
|
|
3
|
+
"version": "0.9.5-next.11b0ca8e.3+11b0ca8",
|
|
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.3",
|
|
17
|
-
"@dedot/providers": "0.9.3",
|
|
18
|
-
"@dedot/runtime-specs": "0.9.3",
|
|
19
|
-
"@dedot/shape": "0.9.3",
|
|
20
|
-
"@dedot/storage": "0.9.3",
|
|
21
|
-
"@dedot/types": "0.9.3",
|
|
22
|
-
"@dedot/utils": "0.9.3"
|
|
16
|
+
"@dedot/codecs": "0.9.5-next.11b0ca8e.3+11b0ca8",
|
|
17
|
+
"@dedot/providers": "0.9.5-next.11b0ca8e.3+11b0ca8",
|
|
18
|
+
"@dedot/runtime-specs": "0.9.5-next.11b0ca8e.3+11b0ca8",
|
|
19
|
+
"@dedot/shape": "0.9.5-next.11b0ca8e.3+11b0ca8",
|
|
20
|
+
"@dedot/storage": "0.9.5-next.11b0ca8e.3+11b0ca8",
|
|
21
|
+
"@dedot/types": "0.9.5-next.11b0ca8e.3+11b0ca8",
|
|
22
|
+
"@dedot/utils": "0.9.5-next.11b0ca8e.3+11b0ca8"
|
|
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": "11b0ca8e2df2c59e12259dc2ba0c61ec91e181cf",
|
|
52
52
|
"module": "./index.js",
|
|
53
53
|
"types": "./index.d.ts"
|
|
54
54
|
}
|