@acala-network/chopsticks-core 1.0.0 → 1.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.
@@ -10,25 +10,20 @@ export interface StorageLayerProvider {
10
10
  * Get the value of a storage key.
11
11
  */
12
12
  get(key: string, cache: boolean): Promise<StorageValue>;
13
- /**
14
- * Fold the storage layer into another layer.
15
- */
16
- foldInto(into: StorageLayer): Promise<StorageLayerProvider | undefined>;
17
- /**
18
- * Fold the storage layer into the parent if it exists.
19
- */
20
- fold(): Promise<void>;
21
13
  /**
22
14
  * Get paged storage keys.
23
15
  */
24
16
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
17
+ /**
18
+ * Find next storage key.
19
+ */
20
+ findNextKey(prefix: string, startKey: string, knownBest?: string): Promise<string | undefined>;
25
21
  }
26
22
  export declare class RemoteStorageLayer implements StorageLayerProvider {
27
23
  #private;
28
24
  constructor(api: Api, at: string, db: Database | undefined);
29
25
  get(key: string, _cache: boolean): Promise<StorageValue>;
30
- foldInto(_into: StorageLayer): Promise<StorageLayerProvider>;
31
- fold(): Promise<void>;
26
+ findNextKey(prefix: string, startKey: string, _knownBest?: string): Promise<string | undefined>;
32
27
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
33
28
  }
34
29
  export declare class StorageLayer implements StorageLayerProvider {
@@ -37,8 +32,7 @@ export declare class StorageLayer implements StorageLayerProvider {
37
32
  get(key: string, cache: boolean): Promise<StorageValue | undefined>;
38
33
  set(key: string, value: StorageValue): void;
39
34
  setAll(values: Record<string, StorageValue | null> | [string, StorageValue | null][]): void;
40
- foldInto(into: StorageLayer): Promise<StorageLayerProvider | undefined>;
41
- fold(): Promise<void>;
35
+ findNextKey(prefix: string, startKey: string, knownBest?: string): Promise<string | undefined>;
42
36
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
43
37
  /**
44
38
  * Merge the storage layer into the given object, can be used to get sotrage diff.
@@ -104,10 +104,10 @@ class RemoteStorageLayer {
104
104
  _class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, data);
105
105
  return data ?? undefined;
106
106
  }
107
- async foldInto(_into) {
108
- return this;
107
+ async findNextKey(prefix, startKey, _knownBest) {
108
+ const keys = await this.getKeysPaged(prefix, 1, startKey);
109
+ return keys[0];
109
110
  }
110
- async fold() {}
111
111
  async getKeysPaged(prefix, pageSize, startKey) {
112
112
  if (pageSize > BATCH_SIZE) throw new Error(`pageSize must be less or equal to ${BATCH_SIZE}`);
113
113
  logger.trace({
@@ -119,7 +119,7 @@ class RemoteStorageLayer {
119
119
  const isChild = (0, _index.isPrefixedChildKey)(prefix);
120
120
  const minPrefixLen = isChild ? _index.CHILD_PREFIX_LENGTH : _index.PREFIX_LENGTH;
121
121
  // can't handle keyCache without prefix
122
- if (prefix.length < minPrefixLen || startKey.length < minPrefixLen) {
122
+ if (prefix === startKey || prefix.length < minPrefixLen || startKey.length < minPrefixLen) {
123
123
  return _class_private_field_get(this, _api).getKeysPaged(prefix, pageSize, startKey, _class_private_field_get(this, _at));
124
124
  }
125
125
  let batchComplete = false;
@@ -243,123 +243,38 @@ class StorageLayer {
243
243
  this.set(key, value || "Deleted");
244
244
  }
245
245
  }
246
- async foldInto(into) {
247
- const newParent = await _class_private_field_get(this, _parent)?.foldInto(into);
248
- for (const deletedPrefix of _class_private_field_get(this, _deletedPrefix)){
249
- into.set(deletedPrefix, "DeletedPrefix");
246
+ async findNextKey(prefix, startKey, knownBest) {
247
+ const maybeBest = _class_private_field_get(this, _keys).find((key)=>key.startsWith(prefix) && key > startKey);
248
+ if (!knownBest) {
249
+ knownBest = maybeBest;
250
+ } else if (maybeBest && maybeBest < knownBest) {
251
+ knownBest = maybeBest;
250
252
  }
251
- for (const [key, value] of _class_private_field_get(this, _store)){
252
- into.set(key, await value);
253
- }
254
- return newParent;
255
- }
256
- async fold() {
257
- if (_class_private_field_get(this, _parent)) {
258
- _class_private_field_set(this, _parent, await _class_private_field_get(this, _parent).foldInto(this));
259
- }
260
- }
261
- async getKeysPaged(prefix, pageSize, startKey) {
262
- let parentFetchComplete = false;
263
- const parentFetchKeys = async (batchSize, startKey)=>{
264
- if (!_class_private_field_get(this, _deletedPrefix).some((dp)=>startKey.startsWith(dp))) {
265
- const newKeys = [];
266
- while(newKeys.length < batchSize){
267
- const remote = await _class_private_field_get(this, _parent)?.getKeysPaged(prefix, batchSize, startKey) ?? [];
268
- if (remote.length) {
269
- startKey = remote[remote.length - 1];
270
- }
271
- for (const key of remote){
272
- if (_class_private_field_get(this, _store).get(key) === "Deleted") {
273
- continue;
274
- }
275
- if (_class_private_field_get(this, _deletedPrefix).some((dp)=>key.startsWith(dp))) {
276
- continue;
277
- }
278
- newKeys.push(key);
279
- }
280
- if (remote.length < batchSize) {
281
- parentFetchComplete = true;
282
- break;
283
- }
284
- }
285
- return newKeys;
286
- } else {
287
- parentFetchComplete = true;
288
- return [];
289
- }
290
- };
291
- const res = [];
292
- const foundNextKey = (key)=>{
293
- // make sure keys are unique and start with the prefix
294
- if (!res.includes(key) && key.startsWith(prefix)) {
295
- res.push(key);
296
- }
297
- };
298
- const iterLocalKeys = (prefix, startKey, includeFirst, endKey)=>{
299
- let idx = _class_private_field_get(this, _keys).findIndex((x)=>x.startsWith(startKey));
300
- if (_class_private_field_get(this, _keys)[idx] !== startKey) {
301
- idx = _class_private_field_get(this, _keys).findIndex((x)=>x.startsWith(prefix) && x > startKey);
302
- const key = _class_private_field_get(this, _keys)[idx];
303
- if (key) {
304
- if (endKey && key >= endKey) {
305
- return startKey;
306
- }
307
- foundNextKey(key);
308
- ++idx;
309
- }
310
- }
311
- if (idx !== -1) {
312
- if (includeFirst) {
313
- const key = _class_private_field_get(this, _keys)[idx];
314
- if (key && key.startsWith(prefix) && key > startKey) {
315
- foundNextKey(key);
316
- }
317
- }
318
- while(res.length < pageSize){
319
- ++idx;
320
- const key = _class_private_field_get(this, _keys)[idx];
321
- if (!key || !key.startsWith(prefix)) {
322
- break;
323
- }
324
- if (endKey && key >= endKey) {
325
- break;
326
- }
327
- foundNextKey(key);
253
+ if (_class_private_field_get(this, _parent) && !_class_private_field_get(this, _deletedPrefix).some((dp)=>dp === prefix)) {
254
+ const parentBest = await _class_private_field_get(this, _parent).findNextKey(prefix, startKey, knownBest);
255
+ if (parentBest) {
256
+ if (!maybeBest) {
257
+ return parentBest;
258
+ } else if (parentBest < maybeBest) {
259
+ return parentBest;
328
260
  }
329
- return _lodash.default.last(res) ?? startKey;
330
261
  }
331
- return startKey;
332
- };
333
- if (prefix !== startKey && _class_private_field_get(this, _keys).find((x)=>x === startKey)) {
334
- startKey = iterLocalKeys(prefix, startKey, false);
335
262
  }
336
- // then iterate the parent keys
337
- let keys = await parentFetchKeys(pageSize - res.length, startKey);
338
- if (keys.length) {
339
- let idx = 0;
340
- while(res.length < pageSize){
341
- const key = keys[idx];
342
- if (!key || !key.startsWith(prefix)) {
343
- if (parentFetchComplete) {
344
- break;
345
- } else {
346
- keys = await parentFetchKeys(pageSize - res.length, _lodash.default.last(keys));
347
- continue;
348
- }
349
- }
350
- const keyPosition = _lodash.default.sortedIndex(_class_private_field_get(this, _keys), key);
351
- const localParentKey = _class_private_field_get(this, _keys)[keyPosition - 1];
352
- if (localParentKey < key) {
353
- startKey = iterLocalKeys(prefix, startKey, false, key);
354
- }
355
- foundNextKey(key);
356
- ++idx;
357
- }
263
+ return knownBest;
264
+ }
265
+ async getKeysPaged(prefix, pageSize, startKey) {
266
+ if (!startKey || startKey === '0x') {
267
+ startKey = prefix;
358
268
  }
359
- if (res.length < pageSize) {
360
- iterLocalKeys(prefix, startKey, prefix === startKey);
269
+ const keys = [];
270
+ while(keys.length < pageSize){
271
+ const next = await this.findNextKey(prefix, startKey, undefined);
272
+ if (!next) break;
273
+ startKey = next;
274
+ if (await this.get(next, false) == "Deleted") continue;
275
+ keys.push(next);
361
276
  }
362
- return res;
277
+ return keys;
363
278
  }
364
279
  /**
365
280
  * Merge the storage layer into the given object, can be used to get sotrage diff.
@@ -41,6 +41,7 @@ export declare const chain_getFinalizedHead: Handler<void, HexString>;
41
41
  export declare const chain_subscribeNewHead: Handler<void, string>;
42
42
  export declare const chain_subscribeFinalizedHeads: Handler<void, string>;
43
43
  export declare const chain_unsubscribeNewHead: Handler<[string], void>;
44
+ export declare const archive_unstable_hashByHeight: Handler<[number | `0x${string}` | `0x${string}`[] | number[] | null], `0x${string}` | (`0x${string}` | null)[] | null>;
44
45
  export declare const chain_getHead: Handler<[number | `0x${string}` | `0x${string}`[] | number[] | null], `0x${string}` | (`0x${string}` | null)[] | null>;
45
46
  export declare const chain_subscribeNewHeads: Handler<void, string>;
46
47
  export declare const chain_unsubscribeNewHeads: Handler<[string], void>;
@@ -9,6 +9,9 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
+ archive_unstable_hashByHeight: function() {
13
+ return archive_unstable_hashByHeight;
14
+ },
12
15
  chain_getBlock: function() {
13
16
  return chain_getBlock;
14
17
  },
@@ -109,6 +112,7 @@ const chain_subscribeFinalizedHeads = async (context, _params, { subscribe })=>{
109
112
  const chain_unsubscribeNewHead = async (_context, [subid], { unsubscribe })=>{
110
113
  unsubscribe(subid);
111
114
  };
115
+ const archive_unstable_hashByHeight = chain_getBlockHash;
112
116
  const chain_getHead = chain_getBlockHash;
113
117
  const chain_subscribeNewHeads = chain_subscribeNewHead;
114
118
  const chain_unsubscribeNewHeads = chain_unsubscribeNewHead;
@@ -55,6 +55,7 @@ declare const handlers: {
55
55
  chain_subscribeNewHead: import("../shared.js").Handler<void, string>;
56
56
  chain_subscribeFinalizedHeads: import("../shared.js").Handler<void, string>;
57
57
  chain_unsubscribeNewHead: import("../shared.js").Handler<[string], void>;
58
+ archive_unstable_hashByHeight: import("../shared.js").Handler<[number | `0x${string}` | `0x${string}`[] | number[] | null], `0x${string}` | (`0x${string}` | null)[] | null>;
58
59
  chain_getHead: import("../shared.js").Handler<[number | `0x${string}` | `0x${string}`[] | number[] | null], `0x${string}` | (`0x${string}` | null)[] | null>;
59
60
  chain_subscribeNewHeads: import("../shared.js").Handler<void, string>;
60
61
  chain_unsubscribeNewHeads: import("../shared.js").Handler<[string], void>;
@@ -10,25 +10,20 @@ export interface StorageLayerProvider {
10
10
  * Get the value of a storage key.
11
11
  */
12
12
  get(key: string, cache: boolean): Promise<StorageValue>;
13
- /**
14
- * Fold the storage layer into another layer.
15
- */
16
- foldInto(into: StorageLayer): Promise<StorageLayerProvider | undefined>;
17
- /**
18
- * Fold the storage layer into the parent if it exists.
19
- */
20
- fold(): Promise<void>;
21
13
  /**
22
14
  * Get paged storage keys.
23
15
  */
24
16
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
17
+ /**
18
+ * Find next storage key.
19
+ */
20
+ findNextKey(prefix: string, startKey: string, knownBest?: string): Promise<string | undefined>;
25
21
  }
26
22
  export declare class RemoteStorageLayer implements StorageLayerProvider {
27
23
  #private;
28
24
  constructor(api: Api, at: string, db: Database | undefined);
29
25
  get(key: string, _cache: boolean): Promise<StorageValue>;
30
- foldInto(_into: StorageLayer): Promise<StorageLayerProvider>;
31
- fold(): Promise<void>;
26
+ findNextKey(prefix: string, startKey: string, _knownBest?: string): Promise<string | undefined>;
32
27
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
33
28
  }
34
29
  export declare class StorageLayer implements StorageLayerProvider {
@@ -37,8 +32,7 @@ export declare class StorageLayer implements StorageLayerProvider {
37
32
  get(key: string, cache: boolean): Promise<StorageValue | undefined>;
38
33
  set(key: string, value: StorageValue): void;
39
34
  setAll(values: Record<string, StorageValue | null> | [string, StorageValue | null][]): void;
40
- foldInto(into: StorageLayer): Promise<StorageLayerProvider | undefined>;
41
- fold(): Promise<void>;
35
+ findNextKey(prefix: string, startKey: string, knownBest?: string): Promise<string | undefined>;
42
36
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
43
37
  /**
44
38
  * Merge the storage layer into the given object, can be used to get sotrage diff.
@@ -37,10 +37,10 @@ export class RemoteStorageLayer {
37
37
  this.#db?.saveStorage(this.#at, key, data);
38
38
  return data ?? undefined;
39
39
  }
40
- async foldInto(_into) {
41
- return this;
40
+ async findNextKey(prefix, startKey, _knownBest) {
41
+ const keys = await this.getKeysPaged(prefix, 1, startKey);
42
+ return keys[0];
42
43
  }
43
- async fold() {}
44
44
  async getKeysPaged(prefix, pageSize, startKey) {
45
45
  if (pageSize > BATCH_SIZE) throw new Error(`pageSize must be less or equal to ${BATCH_SIZE}`);
46
46
  logger.trace({
@@ -52,7 +52,7 @@ export class RemoteStorageLayer {
52
52
  const isChild = isPrefixedChildKey(prefix);
53
53
  const minPrefixLen = isChild ? CHILD_PREFIX_LENGTH : PREFIX_LENGTH;
54
54
  // can't handle keyCache without prefix
55
- if (prefix.length < minPrefixLen || startKey.length < minPrefixLen) {
55
+ if (prefix === startKey || prefix.length < minPrefixLen || startKey.length < minPrefixLen) {
56
56
  return this.#api.getKeysPaged(prefix, pageSize, startKey, this.#at);
57
57
  }
58
58
  let batchComplete = false;
@@ -172,123 +172,38 @@ export class StorageLayer {
172
172
  this.set(key, value || "Deleted");
173
173
  }
174
174
  }
175
- async foldInto(into) {
176
- const newParent = await this.#parent?.foldInto(into);
177
- for (const deletedPrefix of this.#deletedPrefix){
178
- into.set(deletedPrefix, "DeletedPrefix");
179
- }
180
- for (const [key, value] of this.#store){
181
- into.set(key, await value);
182
- }
183
- return newParent;
184
- }
185
- async fold() {
186
- if (this.#parent) {
187
- this.#parent = await this.#parent.foldInto(this);
188
- }
189
- }
190
- async getKeysPaged(prefix, pageSize, startKey) {
191
- let parentFetchComplete = false;
192
- const parentFetchKeys = async (batchSize, startKey)=>{
193
- if (!this.#deletedPrefix.some((dp)=>startKey.startsWith(dp))) {
194
- const newKeys = [];
195
- while(newKeys.length < batchSize){
196
- const remote = await this.#parent?.getKeysPaged(prefix, batchSize, startKey) ?? [];
197
- if (remote.length) {
198
- startKey = remote[remote.length - 1];
199
- }
200
- for (const key of remote){
201
- if (this.#store.get(key) === "Deleted") {
202
- continue;
203
- }
204
- if (this.#deletedPrefix.some((dp)=>key.startsWith(dp))) {
205
- continue;
206
- }
207
- newKeys.push(key);
208
- }
209
- if (remote.length < batchSize) {
210
- parentFetchComplete = true;
211
- break;
212
- }
213
- }
214
- return newKeys;
215
- } else {
216
- parentFetchComplete = true;
217
- return [];
218
- }
219
- };
220
- const res = [];
221
- const foundNextKey = (key)=>{
222
- // make sure keys are unique and start with the prefix
223
- if (!res.includes(key) && key.startsWith(prefix)) {
224
- res.push(key);
225
- }
226
- };
227
- const iterLocalKeys = (prefix, startKey, includeFirst, endKey)=>{
228
- let idx = this.#keys.findIndex((x)=>x.startsWith(startKey));
229
- if (this.#keys[idx] !== startKey) {
230
- idx = this.#keys.findIndex((x)=>x.startsWith(prefix) && x > startKey);
231
- const key = this.#keys[idx];
232
- if (key) {
233
- if (endKey && key >= endKey) {
234
- return startKey;
235
- }
236
- foundNextKey(key);
237
- ++idx;
175
+ async findNextKey(prefix, startKey, knownBest) {
176
+ const maybeBest = this.#keys.find((key)=>key.startsWith(prefix) && key > startKey);
177
+ if (!knownBest) {
178
+ knownBest = maybeBest;
179
+ } else if (maybeBest && maybeBest < knownBest) {
180
+ knownBest = maybeBest;
181
+ }
182
+ if (this.#parent && !this.#deletedPrefix.some((dp)=>dp === prefix)) {
183
+ const parentBest = await this.#parent.findNextKey(prefix, startKey, knownBest);
184
+ if (parentBest) {
185
+ if (!maybeBest) {
186
+ return parentBest;
187
+ } else if (parentBest < maybeBest) {
188
+ return parentBest;
238
189
  }
239
190
  }
240
- if (idx !== -1) {
241
- if (includeFirst) {
242
- const key = this.#keys[idx];
243
- if (key && key.startsWith(prefix) && key > startKey) {
244
- foundNextKey(key);
245
- }
246
- }
247
- while(res.length < pageSize){
248
- ++idx;
249
- const key = this.#keys[idx];
250
- if (!key || !key.startsWith(prefix)) {
251
- break;
252
- }
253
- if (endKey && key >= endKey) {
254
- break;
255
- }
256
- foundNextKey(key);
257
- }
258
- return _.last(res) ?? startKey;
259
- }
260
- return startKey;
261
- };
262
- if (prefix !== startKey && this.#keys.find((x)=>x === startKey)) {
263
- startKey = iterLocalKeys(prefix, startKey, false);
264
- }
265
- // then iterate the parent keys
266
- let keys = await parentFetchKeys(pageSize - res.length, startKey);
267
- if (keys.length) {
268
- let idx = 0;
269
- while(res.length < pageSize){
270
- const key = keys[idx];
271
- if (!key || !key.startsWith(prefix)) {
272
- if (parentFetchComplete) {
273
- break;
274
- } else {
275
- keys = await parentFetchKeys(pageSize - res.length, _.last(keys));
276
- continue;
277
- }
278
- }
279
- const keyPosition = _.sortedIndex(this.#keys, key);
280
- const localParentKey = this.#keys[keyPosition - 1];
281
- if (localParentKey < key) {
282
- startKey = iterLocalKeys(prefix, startKey, false, key);
283
- }
284
- foundNextKey(key);
285
- ++idx;
286
- }
287
191
  }
288
- if (res.length < pageSize) {
289
- iterLocalKeys(prefix, startKey, prefix === startKey);
290
- }
291
- return res;
192
+ return knownBest;
193
+ }
194
+ async getKeysPaged(prefix, pageSize, startKey) {
195
+ if (!startKey || startKey === '0x') {
196
+ startKey = prefix;
197
+ }
198
+ const keys = [];
199
+ while(keys.length < pageSize){
200
+ const next = await this.findNextKey(prefix, startKey, undefined);
201
+ if (!next) break;
202
+ startKey = next;
203
+ if (await this.get(next, false) == "Deleted") continue;
204
+ keys.push(next);
205
+ }
206
+ return keys;
292
207
  }
293
208
  /**
294
209
  * Merge the storage layer into the given object, can be used to get sotrage diff.
@@ -41,6 +41,7 @@ export declare const chain_getFinalizedHead: Handler<void, HexString>;
41
41
  export declare const chain_subscribeNewHead: Handler<void, string>;
42
42
  export declare const chain_subscribeFinalizedHeads: Handler<void, string>;
43
43
  export declare const chain_unsubscribeNewHead: Handler<[string], void>;
44
+ export declare const archive_unstable_hashByHeight: Handler<[number | `0x${string}` | `0x${string}`[] | number[] | null], `0x${string}` | (`0x${string}` | null)[] | null>;
44
45
  export declare const chain_getHead: Handler<[number | `0x${string}` | `0x${string}`[] | number[] | null], `0x${string}` | (`0x${string}` | null)[] | null>;
45
46
  export declare const chain_subscribeNewHeads: Handler<void, string>;
46
47
  export declare const chain_unsubscribeNewHeads: Handler<[string], void>;
@@ -83,6 +83,7 @@ export const chain_subscribeFinalizedHeads = async (context, _params, { subscrib
83
83
  export const chain_unsubscribeNewHead = async (_context, [subid], { unsubscribe })=>{
84
84
  unsubscribe(subid);
85
85
  };
86
+ export const archive_unstable_hashByHeight = chain_getBlockHash;
86
87
  export const chain_getHead = chain_getBlockHash;
87
88
  export const chain_subscribeNewHeads = chain_subscribeNewHead;
88
89
  export const chain_unsubscribeNewHeads = chain_unsubscribeNewHead;
@@ -55,6 +55,7 @@ declare const handlers: {
55
55
  chain_subscribeNewHead: import("../shared.js").Handler<void, string>;
56
56
  chain_subscribeFinalizedHeads: import("../shared.js").Handler<void, string>;
57
57
  chain_unsubscribeNewHead: import("../shared.js").Handler<[string], void>;
58
+ archive_unstable_hashByHeight: import("../shared.js").Handler<[number | `0x${string}` | `0x${string}`[] | number[] | null], `0x${string}` | (`0x${string}` | null)[] | null>;
58
59
  chain_getHead: import("../shared.js").Handler<[number | `0x${string}` | `0x${string}`[] | number[] | null], `0x${string}` | (`0x${string}` | null)[] | null>;
59
60
  chain_subscribeNewHeads: import("../shared.js").Handler<void, string>;
60
61
  chain_unsubscribeNewHeads: import("../shared.js").Handler<[string], void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks-core",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "author": "Acala Developers <hello@acala.network>",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -11,7 +11,7 @@
11
11
  "depcheck": "npx depcheck"
12
12
  },
13
13
  "dependencies": {
14
- "@acala-network/chopsticks-executor": "1.0.0",
14
+ "@acala-network/chopsticks-executor": "1.0.1",
15
15
  "@polkadot/rpc-provider": "^14.0.1",
16
16
  "@polkadot/types": "^14.0.1",
17
17
  "@polkadot/types-codec": "^14.0.1",