@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.
- package/dist/cjs/blockchain/block.d.ts +4 -0
- package/dist/cjs/blockchain/block.js +13 -0
- package/dist/cjs/blockchain/inherent/parachain/validation-data.js +43 -10
- package/dist/cjs/blockchain/storage-layer.d.ts +12 -0
- package/dist/cjs/blockchain/storage-layer.js +85 -1
- package/dist/cjs/rpc/rpc-spec/storage-common.js +4 -4
- package/dist/esm/blockchain/block.d.ts +4 -0
- package/dist/esm/blockchain/block.js +13 -0
- package/dist/esm/blockchain/inherent/parachain/validation-data.js +43 -10
- package/dist/esm/blockchain/storage-layer.d.ts +12 -0
- package/dist/esm/blockchain/storage-layer.js +85 -1
- package/dist/esm/rpc/rpc-spec/storage-common.js +4 -4
- package/package.json +2 -2
|
@@ -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
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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 (
|
|
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
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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 (
|
|
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
|
|
7
|
-
|
|
8
|
-
|
|
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.
|
|
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.
|
|
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",
|