@acala-network/chopsticks-core 1.2.1 → 1.2.2

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.
@@ -48,6 +48,10 @@ export declare class Block {
48
48
  * Get the block storage by key.
49
49
  */
50
50
  get(key: string): Promise<HexString | undefined>;
51
+ /**
52
+ * Get the block storage by key.
53
+ */
54
+ getMany(keys: string[]): Promise<Array<HexString | undefined>>;
51
55
  read<T extends string>(type: T, query: StorageEntry, ...args: any[]): Promise<import("@polkadot/types/types").DetectCodec<import("@polkadot/types-codec/types").Codec, T> | undefined>;
52
56
  /**
53
57
  * Get paged storage keys.
@@ -127,6 +127,19 @@ class Block {
127
127
  return val;
128
128
  }
129
129
  }
130
+ /**
131
+ * Get the block storage by key.
132
+ */ async getMany(keys) {
133
+ const vals = await this.storage.getMany(keys, true);
134
+ return vals.map((val)=>{
135
+ switch(val){
136
+ case _storagelayer.StorageValueKind.Deleted:
137
+ return undefined;
138
+ default:
139
+ return val;
140
+ }
141
+ });
142
+ }
130
143
  async read(type, query, ...args) {
131
144
  const key = (0, _index.compactHex)(query(...args));
132
145
  const value = await this.get(key);
@@ -12,6 +12,7 @@ const _types = require("@polkadot/types");
12
12
  const _util = require("@polkadot/util");
13
13
  const _utilcrypto = require("@polkadot/util-crypto");
14
14
  const _lodash = /*#__PURE__*/ _interop_require_default(require("lodash"));
15
+ const _logger = require("../../../logger.js");
15
16
  const _index = require("../../../utils/index.js");
16
17
  const _proof = require("../../../utils/proof.js");
17
18
  const _index1 = require("../../../wasm-executor/index.js");
@@ -20,6 +21,9 @@ function _interop_require_default(obj) {
20
21
  default: obj
21
22
  };
22
23
  }
24
+ const logger = _logger.defaultLogger.child({
25
+ name: 'parachain-validation-data'
26
+ });
23
27
  const MOCK_VALIDATION_DATA = {
24
28
  validationData: {
25
29
  relayParentNumber: 1000,
@@ -46,7 +50,7 @@ const MOCK_VALIDATION_DATA = {
46
50
  horizontalMessages: [],
47
51
  downwardMessages: []
48
52
  };
49
- const getValidationData = async (parent)=>{
53
+ const getValidationData = async (parent, fallback = true)=>{
50
54
  const meta = await parent.meta;
51
55
  if (parent.number === 0) {
52
56
  const { trieRootHash, nodes } = await (0, _index1.createProof)(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
@@ -61,15 +65,39 @@ const getValidationData = async (parent)=>{
61
65
  }
62
66
  };
63
67
  }
64
- const extrinsics = await parent.extrinsics;
65
- const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
66
- const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
67
- return firstArg && 'validationData' in firstArg;
68
- });
69
- if (!validationDataExtrinsic) {
70
- throw new Error('Missing validation data from block');
68
+ try {
69
+ const extrinsics = await parent.extrinsics;
70
+ const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
71
+ const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
72
+ return firstArg && 'validationData' in firstArg;
73
+ });
74
+ if (!validationDataExtrinsic) {
75
+ throw new Error('Missing validation data from block');
76
+ }
77
+ return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
78
+ } catch (e) {
79
+ logger.warn('Failed to get validation data from block %d %s', parent.number, e);
80
+ if (fallback) {
81
+ // this could fail due to wasm override that breaks the validation data format
82
+ // so we will try parent's parent
83
+ const grandParent = await parent.parentBlock;
84
+ if (grandParent) {
85
+ const data = await getValidationData(grandParent, false);
86
+ return {
87
+ ...data,
88
+ validationData: {
89
+ ...data.validationData,
90
+ relayParentNumber: data.validationData.relayParentNumber + 2
91
+ }
92
+ };
93
+ } else {
94
+ throw e;
95
+ }
96
+ } else {
97
+ // fallback failed, throw error
98
+ throw e;
99
+ }
71
100
  }
72
- return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
73
101
  };
74
102
  class SetValidationData {
75
103
  async createInherents(newBlock, params) {
@@ -97,7 +125,12 @@ class SetValidationData {
97
125
  if (key === _proof.WELL_KNOWN_KEYS.CURRENT_SLOT) {
98
126
  // increment current slot
99
127
  const relayCurrentSlot = decoded[key] ? meta.registry.createType('Slot', (0, _util.hexToU8a)(decoded[key])).toNumber() : await (0, _index.getCurrentSlot)(parent) * relaySlotIncrease;
100
- const newSlot = meta.registry.createType('Slot', relayCurrentSlot + relaySlotIncrease);
128
+ const newSlot = meta.registry.createType('Slot', relayCurrentSlot + relaySlotIncrease + 1) // +1 to be safe
129
+ ;
130
+ logger.debug({
131
+ relayCurrentSlot,
132
+ newSlot: newSlot.toNumber()
133
+ }, 'Updating relay current slot');
101
134
  newEntries.push([
102
135
  key,
103
136
  (0, _util.u8aToHex)(newSlot.toU8a())
@@ -7,10 +7,18 @@ export declare enum StorageValueKind {
7
7
  }
8
8
  export type StorageValue = string | StorageValueKind | undefined;
9
9
  export interface StorageLayerProvider {
10
+ /**
11
+ * Returns true if key is deleted
12
+ */
13
+ deleted(key: string): boolean;
10
14
  /**
11
15
  * Get the value of a storage key.
12
16
  */
13
17
  get(key: string, cache: boolean): Promise<StorageValue>;
18
+ /**
19
+ * Get the value of many storage keys.
20
+ */
21
+ getMany(keys: string[], _cache: boolean): Promise<StorageValue[]>;
14
22
  /**
15
23
  * Get paged storage keys.
16
24
  */
@@ -23,14 +31,18 @@ export interface StorageLayerProvider {
23
31
  export declare class RemoteStorageLayer implements StorageLayerProvider {
24
32
  #private;
25
33
  constructor(api: Api, at: HexString, db: Database | undefined);
34
+ deleted(_key: string): boolean;
26
35
  get(key: string, _cache: boolean): Promise<StorageValue>;
36
+ getMany(keys: string[], _cache: boolean): Promise<StorageValue[]>;
27
37
  findNextKey(prefix: string, startKey: string, _knownBest?: string): Promise<string | undefined>;
28
38
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
29
39
  }
30
40
  export declare class StorageLayer implements StorageLayerProvider {
31
41
  #private;
32
42
  constructor(parent?: StorageLayerProvider);
43
+ deleted(key: string): boolean;
33
44
  get(key: string, cache: boolean): Promise<StorageValue | undefined>;
45
+ getMany(keys: string[], cache: boolean): Promise<StorageValue[]>;
34
46
  set(key: string, value: StorageValue): void;
35
47
  setAll(values: Record<string, StorageValue | null> | [string, StorageValue | null][]): void;
36
48
  findNextKey(prefix: string, startKey: string, knownBest?: string): Promise<string | undefined>;
@@ -89,6 +89,9 @@ var StorageValueKind = /*#__PURE__*/ function(StorageValueKind) {
89
89
  }({});
90
90
  var _api = /*#__PURE__*/ new WeakMap(), _at = /*#__PURE__*/ new WeakMap(), _db = /*#__PURE__*/ new WeakMap(), _keyCache = /*#__PURE__*/ new WeakMap(), _defaultChildKeyCache = /*#__PURE__*/ new WeakMap();
91
91
  class RemoteStorageLayer {
92
+ deleted(_key) {
93
+ return false;
94
+ }
92
95
  async get(key, _cache) {
93
96
  if (_class_private_field_get(this, _db)) {
94
97
  const res = await _class_private_field_get(this, _db).queryStorage(_class_private_field_get(this, _at), key);
@@ -104,6 +107,48 @@ class RemoteStorageLayer {
104
107
  _class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, data);
105
108
  return data ?? undefined;
106
109
  }
110
+ async getMany(keys, _cache) {
111
+ const result = [];
112
+ let pending = keys.map((key, idx)=>({
113
+ key,
114
+ idx
115
+ }));
116
+ if (_class_private_field_get(this, _db)) {
117
+ const results = await Promise.all(pending.map(({ key })=>_class_private_field_get(this, _db).queryStorage(_class_private_field_get(this, _at), key)));
118
+ const oldPending = pending;
119
+ pending = [];
120
+ results.forEach((res, idx)=>{
121
+ if (res) {
122
+ result[idx] = res.value ?? undefined;
123
+ } else {
124
+ pending.push({
125
+ key: oldPending[idx].key,
126
+ idx
127
+ });
128
+ }
129
+ });
130
+ }
131
+ if (pending.length) {
132
+ logger.trace({
133
+ at: _class_private_field_get(this, _at),
134
+ keys
135
+ }, 'RemoteStorageLayer getMany');
136
+ const data = await _class_private_field_get(this, _api).getStorageBatch('0x', pending.map(({ key })=>key), _class_private_field_get(this, _at));
137
+ data.forEach(([, res], idx)=>{
138
+ result[pending[idx].idx] = res ?? undefined;
139
+ });
140
+ if (_class_private_field_get(this, _db)?.saveStorageBatch) {
141
+ _class_private_field_get(this, _db)?.saveStorageBatch(data.map(([key, value])=>({
142
+ key,
143
+ value,
144
+ blockHash: _class_private_field_get(this, _at)
145
+ })));
146
+ } else if (_class_private_field_get(this, _db)) {
147
+ data.forEach(([key, value])=>_class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, value));
148
+ }
149
+ }
150
+ return result;
151
+ }
107
152
  async findNextKey(prefix, startKey, _knownBest) {
108
153
  const keys = await this.getKeysPaged(prefix, 1, startKey);
109
154
  return keys[0];
@@ -205,6 +250,18 @@ class RemoteStorageLayer {
205
250
  }
206
251
  var _store = /*#__PURE__*/ new WeakMap(), _keys = /*#__PURE__*/ new WeakMap(), _deletedPrefix = /*#__PURE__*/ new WeakMap(), _parent = /*#__PURE__*/ new WeakMap(), _addKey = /*#__PURE__*/ new WeakSet(), _removeKey = /*#__PURE__*/ new WeakSet();
207
252
  class StorageLayer {
253
+ deleted(key) {
254
+ if (_class_private_field_get(this, _store).has(key)) {
255
+ return _class_private_field_get(this, _store).get(key) === "Deleted";
256
+ }
257
+ if (_class_private_field_get(this, _deletedPrefix).some((dp)=>key.startsWith(dp))) {
258
+ return true;
259
+ }
260
+ if (_class_private_field_get(this, _parent)) {
261
+ return _class_private_field_get(this, _parent).deleted(key);
262
+ }
263
+ return false;
264
+ }
208
265
  async get(key, cache) {
209
266
  if (_class_private_field_get(this, _store).has(key)) {
210
267
  return _class_private_field_get(this, _store).get(key);
@@ -221,6 +278,33 @@ class StorageLayer {
221
278
  }
222
279
  return undefined;
223
280
  }
281
+ async getMany(keys, cache) {
282
+ const result = [];
283
+ const pending = [];
284
+ const preloadedPromises = keys.map(async (key, idx)=>{
285
+ if (_class_private_field_get(this, _store).has(key)) {
286
+ result[idx] = await _class_private_field_get(this, _store).get(key);
287
+ } else if (_class_private_field_get(this, _deletedPrefix).some((dp)=>key.startsWith(dp))) {
288
+ result[idx] = "Deleted";
289
+ } else {
290
+ pending.push({
291
+ key,
292
+ idx
293
+ });
294
+ }
295
+ });
296
+ if (pending.length && _class_private_field_get(this, _parent)) {
297
+ const vals = await _class_private_field_get(this, _parent).getMany(pending.map((p)=>p.key), false);
298
+ vals.forEach((val, idx)=>{
299
+ if (cache) {
300
+ _class_private_field_get(this, _store).set(pending[idx].key, val);
301
+ }
302
+ result[pending[idx].idx] = val;
303
+ });
304
+ }
305
+ await Promise.all(preloadedPromises);
306
+ return result;
307
+ }
224
308
  set(key, value) {
225
309
  switch(value){
226
310
  case "Deleted":
@@ -283,7 +367,7 @@ class StorageLayer {
283
367
  const next = await this.findNextKey(prefix, startKey, undefined);
284
368
  if (!next) break;
285
369
  startKey = next;
286
- if (await this.get(next, false) === "Deleted") continue;
370
+ if (this.deleted(next)) continue;
287
371
  keys.push(next);
288
372
  }
289
373
  return keys;
@@ -24,10 +24,10 @@ async function getDescendantValues(block, params) {
24
24
  ...params,
25
25
  pageSize: PAGE_SIZE
26
26
  });
27
- const items = await Promise.all(keys.map((key)=>block.get(key).then((value)=>({
28
- key,
29
- value
30
- }))));
27
+ const items = (await block.getMany(keys)).map((value, idx)=>({
28
+ key: keys[idx],
29
+ value
30
+ }));
31
31
  if (keys.length < PAGE_SIZE) {
32
32
  return {
33
33
  items,
@@ -48,6 +48,10 @@ export declare class Block {
48
48
  * Get the block storage by key.
49
49
  */
50
50
  get(key: string): Promise<HexString | undefined>;
51
+ /**
52
+ * Get the block storage by key.
53
+ */
54
+ getMany(keys: string[]): Promise<Array<HexString | undefined>>;
51
55
  read<T extends string>(type: T, query: StorageEntry, ...args: any[]): Promise<import("@polkadot/types/types").DetectCodec<import("@polkadot/types-codec/types").Codec, T> | undefined>;
52
56
  /**
53
57
  * Get paged storage keys.
@@ -117,6 +117,19 @@ import { RemoteStorageLayer, StorageLayer, StorageValueKind } from './storage-la
117
117
  return val;
118
118
  }
119
119
  }
120
+ /**
121
+ * Get the block storage by key.
122
+ */ async getMany(keys) {
123
+ const vals = await this.storage.getMany(keys, true);
124
+ return vals.map((val)=>{
125
+ switch(val){
126
+ case StorageValueKind.Deleted:
127
+ return undefined;
128
+ default:
129
+ return val;
130
+ }
131
+ });
132
+ }
120
133
  async read(type, query, ...args) {
121
134
  const key = compactHex(query(...args));
122
135
  const value = await this.get(key);
@@ -2,9 +2,13 @@ import { GenericExtrinsic } from '@polkadot/types';
2
2
  import { hexToU8a, u8aConcat, u8aToHex } from '@polkadot/util';
3
3
  import { blake2AsHex, blake2AsU8a } from '@polkadot/util-crypto';
4
4
  import _ from 'lodash';
5
+ import { defaultLogger } from '../../../logger.js';
5
6
  import { compactHex, getCurrentSlot, getParaId } from '../../../utils/index.js';
6
7
  import { dmqMqcHead, hrmpChannels, hrmpEgressChannelIndex, hrmpIngressChannelIndex, paraHead, upgradeGoAheadSignal, WELL_KNOWN_KEYS } from '../../../utils/proof.js';
7
8
  import { createProof, decodeProof } from '../../../wasm-executor/index.js';
9
+ const logger = defaultLogger.child({
10
+ name: 'parachain-validation-data'
11
+ });
8
12
  const MOCK_VALIDATION_DATA = {
9
13
  validationData: {
10
14
  relayParentNumber: 1000,
@@ -31,7 +35,7 @@ const MOCK_VALIDATION_DATA = {
31
35
  horizontalMessages: [],
32
36
  downwardMessages: []
33
37
  };
34
- const getValidationData = async (parent)=>{
38
+ const getValidationData = async (parent, fallback = true)=>{
35
39
  const meta = await parent.meta;
36
40
  if (parent.number === 0) {
37
41
  const { trieRootHash, nodes } = await createProof(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
@@ -46,15 +50,39 @@ const getValidationData = async (parent)=>{
46
50
  }
47
51
  };
48
52
  }
49
- const extrinsics = await parent.extrinsics;
50
- const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
51
- const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
52
- return firstArg && 'validationData' in firstArg;
53
- });
54
- if (!validationDataExtrinsic) {
55
- throw new Error('Missing validation data from block');
53
+ try {
54
+ const extrinsics = await parent.extrinsics;
55
+ const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
56
+ const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
57
+ return firstArg && 'validationData' in firstArg;
58
+ });
59
+ if (!validationDataExtrinsic) {
60
+ throw new Error('Missing validation data from block');
61
+ }
62
+ return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
63
+ } catch (e) {
64
+ logger.warn('Failed to get validation data from block %d %s', parent.number, e);
65
+ if (fallback) {
66
+ // this could fail due to wasm override that breaks the validation data format
67
+ // so we will try parent's parent
68
+ const grandParent = await parent.parentBlock;
69
+ if (grandParent) {
70
+ const data = await getValidationData(grandParent, false);
71
+ return {
72
+ ...data,
73
+ validationData: {
74
+ ...data.validationData,
75
+ relayParentNumber: data.validationData.relayParentNumber + 2
76
+ }
77
+ };
78
+ } else {
79
+ throw e;
80
+ }
81
+ } else {
82
+ // fallback failed, throw error
83
+ throw e;
84
+ }
56
85
  }
57
- return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
58
86
  };
59
87
  export class SetValidationData {
60
88
  async createInherents(newBlock, params) {
@@ -82,7 +110,12 @@ export class SetValidationData {
82
110
  if (key === WELL_KNOWN_KEYS.CURRENT_SLOT) {
83
111
  // increment current slot
84
112
  const relayCurrentSlot = decoded[key] ? meta.registry.createType('Slot', hexToU8a(decoded[key])).toNumber() : await getCurrentSlot(parent) * relaySlotIncrease;
85
- const newSlot = meta.registry.createType('Slot', relayCurrentSlot + relaySlotIncrease);
113
+ const newSlot = meta.registry.createType('Slot', relayCurrentSlot + relaySlotIncrease + 1) // +1 to be safe
114
+ ;
115
+ logger.debug({
116
+ relayCurrentSlot,
117
+ newSlot: newSlot.toNumber()
118
+ }, 'Updating relay current slot');
86
119
  newEntries.push([
87
120
  key,
88
121
  u8aToHex(newSlot.toU8a())
@@ -7,10 +7,18 @@ export declare enum StorageValueKind {
7
7
  }
8
8
  export type StorageValue = string | StorageValueKind | undefined;
9
9
  export interface StorageLayerProvider {
10
+ /**
11
+ * Returns true if key is deleted
12
+ */
13
+ deleted(key: string): boolean;
10
14
  /**
11
15
  * Get the value of a storage key.
12
16
  */
13
17
  get(key: string, cache: boolean): Promise<StorageValue>;
18
+ /**
19
+ * Get the value of many storage keys.
20
+ */
21
+ getMany(keys: string[], _cache: boolean): Promise<StorageValue[]>;
14
22
  /**
15
23
  * Get paged storage keys.
16
24
  */
@@ -23,14 +31,18 @@ export interface StorageLayerProvider {
23
31
  export declare class RemoteStorageLayer implements StorageLayerProvider {
24
32
  #private;
25
33
  constructor(api: Api, at: HexString, db: Database | undefined);
34
+ deleted(_key: string): boolean;
26
35
  get(key: string, _cache: boolean): Promise<StorageValue>;
36
+ getMany(keys: string[], _cache: boolean): Promise<StorageValue[]>;
27
37
  findNextKey(prefix: string, startKey: string, _knownBest?: string): Promise<string | undefined>;
28
38
  getKeysPaged(prefix: string, pageSize: number, startKey: string): Promise<string[]>;
29
39
  }
30
40
  export declare class StorageLayer implements StorageLayerProvider {
31
41
  #private;
32
42
  constructor(parent?: StorageLayerProvider);
43
+ deleted(key: string): boolean;
33
44
  get(key: string, cache: boolean): Promise<StorageValue | undefined>;
45
+ getMany(keys: string[], cache: boolean): Promise<StorageValue[]>;
34
46
  set(key: string, value: StorageValue): void;
35
47
  setAll(values: Record<string, StorageValue | null> | [string, StorageValue | null][]): void;
36
48
  findNextKey(prefix: string, startKey: string, knownBest?: string): Promise<string | undefined>;
@@ -22,6 +22,9 @@ export class RemoteStorageLayer {
22
22
  this.#at = at;
23
23
  this.#db = db;
24
24
  }
25
+ deleted(_key) {
26
+ return false;
27
+ }
25
28
  async get(key, _cache) {
26
29
  if (this.#db) {
27
30
  const res = await this.#db.queryStorage(this.#at, key);
@@ -37,6 +40,48 @@ export class RemoteStorageLayer {
37
40
  this.#db?.saveStorage(this.#at, key, data);
38
41
  return data ?? undefined;
39
42
  }
43
+ async getMany(keys, _cache) {
44
+ const result = [];
45
+ let pending = keys.map((key, idx)=>({
46
+ key,
47
+ idx
48
+ }));
49
+ if (this.#db) {
50
+ const results = await Promise.all(pending.map(({ key })=>this.#db.queryStorage(this.#at, key)));
51
+ const oldPending = pending;
52
+ pending = [];
53
+ results.forEach((res, idx)=>{
54
+ if (res) {
55
+ result[idx] = res.value ?? undefined;
56
+ } else {
57
+ pending.push({
58
+ key: oldPending[idx].key,
59
+ idx
60
+ });
61
+ }
62
+ });
63
+ }
64
+ if (pending.length) {
65
+ logger.trace({
66
+ at: this.#at,
67
+ keys
68
+ }, 'RemoteStorageLayer getMany');
69
+ const data = await this.#api.getStorageBatch('0x', pending.map(({ key })=>key), this.#at);
70
+ data.forEach(([, res], idx)=>{
71
+ result[pending[idx].idx] = res ?? undefined;
72
+ });
73
+ if (this.#db?.saveStorageBatch) {
74
+ this.#db?.saveStorageBatch(data.map(([key, value])=>({
75
+ key,
76
+ value,
77
+ blockHash: this.#at
78
+ })));
79
+ } else if (this.#db) {
80
+ data.forEach(([key, value])=>this.#db?.saveStorage(this.#at, key, value));
81
+ }
82
+ }
83
+ return result;
84
+ }
40
85
  async findNextKey(prefix, startKey, _knownBest) {
41
86
  const keys = await this.getKeysPaged(prefix, 1, startKey);
42
87
  return keys[0];
@@ -134,6 +179,18 @@ export class StorageLayer {
134
179
  this.#keys.splice(idx, 1);
135
180
  }
136
181
  }
182
+ deleted(key) {
183
+ if (this.#store.has(key)) {
184
+ return this.#store.get(key) === "Deleted";
185
+ }
186
+ if (this.#deletedPrefix.some((dp)=>key.startsWith(dp))) {
187
+ return true;
188
+ }
189
+ if (this.#parent) {
190
+ return this.#parent.deleted(key);
191
+ }
192
+ return false;
193
+ }
137
194
  async get(key, cache) {
138
195
  if (this.#store.has(key)) {
139
196
  return this.#store.get(key);
@@ -150,6 +207,33 @@ export class StorageLayer {
150
207
  }
151
208
  return undefined;
152
209
  }
210
+ async getMany(keys, cache) {
211
+ const result = [];
212
+ const pending = [];
213
+ const preloadedPromises = keys.map(async (key, idx)=>{
214
+ if (this.#store.has(key)) {
215
+ result[idx] = await this.#store.get(key);
216
+ } else if (this.#deletedPrefix.some((dp)=>key.startsWith(dp))) {
217
+ result[idx] = "Deleted";
218
+ } else {
219
+ pending.push({
220
+ key,
221
+ idx
222
+ });
223
+ }
224
+ });
225
+ if (pending.length && this.#parent) {
226
+ const vals = await this.#parent.getMany(pending.map((p)=>p.key), false);
227
+ vals.forEach((val, idx)=>{
228
+ if (cache) {
229
+ this.#store.set(pending[idx].key, val);
230
+ }
231
+ result[pending[idx].idx] = val;
232
+ });
233
+ }
234
+ await Promise.all(preloadedPromises);
235
+ return result;
236
+ }
153
237
  set(key, value) {
154
238
  switch(value){
155
239
  case "Deleted":
@@ -212,7 +296,7 @@ export class StorageLayer {
212
296
  const next = await this.findNextKey(prefix, startKey, undefined);
213
297
  if (!next) break;
214
298
  startKey = next;
215
- if (await this.get(next, false) === "Deleted") continue;
299
+ if (this.deleted(next)) continue;
216
300
  keys.push(next);
217
301
  }
218
302
  return keys;
@@ -3,10 +3,10 @@ export async function getDescendantValues(block, params) {
3
3
  ...params,
4
4
  pageSize: PAGE_SIZE
5
5
  });
6
- const items = await Promise.all(keys.map((key)=>block.get(key).then((value)=>({
7
- key,
8
- value
9
- }))));
6
+ const items = (await block.getMany(keys)).map((value, idx)=>({
7
+ key: keys[idx],
8
+ value
9
+ }));
10
10
  if (keys.length < PAGE_SIZE) {
11
11
  return {
12
12
  items,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks-core",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "author": "Acala Developers <hello@acala.network>",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -14,7 +14,7 @@
14
14
  "depcheck": "npx depcheck"
15
15
  },
16
16
  "dependencies": {
17
- "@acala-network/chopsticks-executor": "1.2.1",
17
+ "@acala-network/chopsticks-executor": "1.2.2",
18
18
  "@polkadot/rpc-provider": "^16.4.1",
19
19
  "@polkadot/types": "^16.4.1",
20
20
  "@polkadot/types-codec": "^16.4.1",