@acala-network/chopsticks 0.6.4 → 0.6.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.
- package/lib/blockchain/block-builder.js +63 -12
- package/lib/blockchain/storage-layer.js +35 -2
- package/lib/blockchain/txpool.js +1 -1
- package/lib/executor.js +12 -3
- package/lib/rpc/shared.d.ts +1 -1
- package/lib/utils/key-cache.d.ts +10 -0
- package/lib/utils/key-cache.js +66 -0
- package/lib/xcm/index.d.ts +1 -1
- package/package.json +6 -6
|
@@ -135,20 +135,71 @@ const buildBlock = async (head, inherents, extrinsics, ump, onApplyExtrinsicErro
|
|
|
135
135
|
const meta = await head.meta;
|
|
136
136
|
layer = new storage_layer_1.StorageLayer(head.storage);
|
|
137
137
|
for (const [paraId, upwardMessages] of Object.entries(ump)) {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
138
|
+
const upwardMessagesU8a = upwardMessages.map((x) => (0, util_1.hexToU8a)(x));
|
|
139
|
+
const messagesCount = upwardMessages.length;
|
|
140
|
+
const messagesSize = upwardMessagesU8a.map((x) => x.length).reduce((s, i) => s + i, 0);
|
|
141
|
+
if (meta.query.ump) {
|
|
142
|
+
const queueSize = meta.registry.createType('(u32, u32)', [messagesCount, messagesSize]);
|
|
143
|
+
const messages = meta.registry.createType('Vec<Bytes>', upwardMessages);
|
|
144
|
+
// TODO: make sure we append instead of replace
|
|
145
|
+
layer.setAll([
|
|
146
|
+
[(0, utils_1.compactHex)(meta.query.ump.relayDispatchQueues(paraId)), messages.toHex()],
|
|
147
|
+
[(0, utils_1.compactHex)(meta.query.ump.relayDispatchQueueSize(paraId)), queueSize.toHex()],
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
else if (meta.query.messageQueue) {
|
|
151
|
+
// TODO: make sure we append instead of replace
|
|
152
|
+
const origin = { ump: { para: paraId } };
|
|
153
|
+
let last = 0;
|
|
154
|
+
let heap = new Uint8Array(0);
|
|
155
|
+
for (const message of upwardMessagesU8a) {
|
|
156
|
+
const payloadLen = message.length;
|
|
157
|
+
const header = meta.registry.createType('(u32, bool)', [payloadLen, false]);
|
|
158
|
+
last = heap.length;
|
|
159
|
+
heap = (0, util_1.u8aConcat)(heap, header.toU8a(), message);
|
|
160
|
+
}
|
|
161
|
+
layer.setAll([
|
|
162
|
+
[
|
|
163
|
+
(0, utils_1.compactHex)(meta.query.messageQueue.bookStateFor(origin)),
|
|
164
|
+
meta.registry
|
|
165
|
+
.createType('PalletMessageQueueBookState', {
|
|
166
|
+
begin: 0,
|
|
167
|
+
end: 1,
|
|
168
|
+
count: 1,
|
|
169
|
+
readyNeighbours: { prev: origin, next: origin },
|
|
170
|
+
messageCount: messagesCount,
|
|
171
|
+
size_: messagesSize,
|
|
172
|
+
})
|
|
173
|
+
.toHex(),
|
|
174
|
+
],
|
|
175
|
+
[
|
|
176
|
+
(0, utils_1.compactHex)(meta.query.messageQueue.serviceHead(origin)),
|
|
177
|
+
meta.registry.createType('PolkadotRuntimeParachainsInclusionAggregateMessageOrigin', origin).toHex(),
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
(0, utils_1.compactHex)(meta.query.messageQueue.pages(origin, 0)),
|
|
181
|
+
meta.registry
|
|
182
|
+
.createType('PalletMessageQueuePage', {
|
|
183
|
+
remaining: messagesCount,
|
|
184
|
+
remaining_size: messagesSize,
|
|
185
|
+
first_index: 0,
|
|
186
|
+
first: 0,
|
|
187
|
+
last,
|
|
188
|
+
heap: (0, util_1.compactAddLength)(heap),
|
|
189
|
+
})
|
|
190
|
+
.toHex(),
|
|
191
|
+
],
|
|
192
|
+
]);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
throw new Error('Unknown ump storage');
|
|
196
|
+
}
|
|
148
197
|
logger.trace({ paraId, upwardMessages: (0, logger_1.truncate)(upwardMessages) }, 'Pushed UMP');
|
|
149
198
|
}
|
|
150
|
-
|
|
151
|
-
|
|
199
|
+
if (meta.query.ump) {
|
|
200
|
+
const needsDispatch = meta.registry.createType('Vec<u32>', Object.keys(ump));
|
|
201
|
+
layer.set((0, utils_1.compactHex)(meta.query.ump.needsDispatch()), needsDispatch.toHex());
|
|
202
|
+
}
|
|
152
203
|
}
|
|
153
204
|
const { block: newBlock } = await initNewBlock(head, header, inherents, layer);
|
|
154
205
|
logger.info({
|
|
@@ -6,11 +6,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.StorageLayer = exports.RemoteStorageLayer = void 0;
|
|
7
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
|
+
const key_cache_1 = __importDefault(require("../utils/key-cache"));
|
|
9
10
|
const logger = logger_1.defaultLogger.child({ name: 'layer' });
|
|
11
|
+
const BATCH_SIZE = 1000;
|
|
10
12
|
class RemoteStorageLayer {
|
|
11
13
|
#api;
|
|
12
14
|
#at;
|
|
13
15
|
#db;
|
|
16
|
+
#keyCache = new key_cache_1.default();
|
|
14
17
|
constructor(api, at, db) {
|
|
15
18
|
this.#api = api;
|
|
16
19
|
this.#at = at;
|
|
@@ -33,8 +36,39 @@ class RemoteStorageLayer {
|
|
|
33
36
|
}
|
|
34
37
|
async fold() { }
|
|
35
38
|
async getKeysPaged(prefix, pageSize, startKey) {
|
|
39
|
+
if (pageSize > BATCH_SIZE)
|
|
40
|
+
throw new Error(`pageSize must be less or equal to ${BATCH_SIZE}`);
|
|
36
41
|
logger.trace({ at: this.#at, prefix, pageSize, startKey }, 'RemoteStorageLayer getKeysPaged');
|
|
37
|
-
|
|
42
|
+
// can't handle keyCache without prefix
|
|
43
|
+
if (prefix.length < 66) {
|
|
44
|
+
return this.#api.getKeysPaged(prefix, pageSize, startKey, this.#at);
|
|
45
|
+
}
|
|
46
|
+
let batchComplete = false;
|
|
47
|
+
const keysPaged = [];
|
|
48
|
+
while (keysPaged.length < pageSize) {
|
|
49
|
+
const nextKey = await this.#keyCache.next(startKey);
|
|
50
|
+
if (nextKey) {
|
|
51
|
+
keysPaged.push(nextKey);
|
|
52
|
+
startKey = nextKey;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// batch fetch was completed
|
|
56
|
+
if (batchComplete) {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
// fetch a batch of keys
|
|
60
|
+
const batch = await this.#api.getKeysPaged(prefix, BATCH_SIZE, startKey, this.#at);
|
|
61
|
+
batchComplete = batch.length < BATCH_SIZE;
|
|
62
|
+
// feed the key cache
|
|
63
|
+
if (batch.length > 0) {
|
|
64
|
+
this.#keyCache.feed([startKey, ...batch]);
|
|
65
|
+
}
|
|
66
|
+
if (batch.length === 0) {
|
|
67
|
+
// no more keys were found
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return keysPaged;
|
|
38
72
|
}
|
|
39
73
|
}
|
|
40
74
|
exports.RemoteStorageLayer = RemoteStorageLayer;
|
|
@@ -128,7 +162,6 @@ class StorageLayer {
|
|
|
128
162
|
}
|
|
129
163
|
async getKeysPaged(prefix, pageSize, startKey) {
|
|
130
164
|
if (!this.#deletedPrefix.some((prefix) => startKey.startsWith(prefix))) {
|
|
131
|
-
// TODO: maintain a list of fetched ranges to avoid fetching the same range multiple times
|
|
132
165
|
const remote = (await this.#parent?.getKeysPaged(prefix, pageSize, startKey)) ?? [];
|
|
133
166
|
for (const key of remote) {
|
|
134
167
|
if (this.#deletedPrefix.some((prefix) => key.startsWith(prefix))) {
|
package/lib/blockchain/txpool.js
CHANGED
package/lib/executor.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getAuraSlotDuration = exports.emptyTaskHandler = exports.taskHandler = exports.runTask = exports.createProof = exports.decodeProof = exports.calculateStateRoot = exports.getRuntimeVersion = void 0;
|
|
7
7
|
const util_1 = require("@polkadot/util");
|
|
8
|
+
const key_cache_1 = require("./utils/key-cache");
|
|
8
9
|
const chopsticks_executor_1 = require("@acala-network/chopsticks-executor");
|
|
9
10
|
const logger_1 = require("./logger");
|
|
10
11
|
const lodash_1 = __importDefault(require("lodash"));
|
|
@@ -48,16 +49,24 @@ const runTask = async (task, callback = exports.emptyTaskHandler) => {
|
|
|
48
49
|
};
|
|
49
50
|
exports.runTask = runTask;
|
|
50
51
|
const taskHandler = (block) => {
|
|
52
|
+
const batchSize = 1000;
|
|
51
53
|
return {
|
|
52
54
|
getStorage: async function (key) {
|
|
53
55
|
return block.get(key);
|
|
54
56
|
},
|
|
55
57
|
getPrefixKeys: async function (key) {
|
|
56
|
-
|
|
58
|
+
let keys = [];
|
|
59
|
+
let startKey = key;
|
|
60
|
+
while (startKey) {
|
|
61
|
+
const batch = await block.getKeysPaged({ prefix: key.slice(0, key_cache_1.PREFIX_LENGTH), pageSize: batchSize, startKey });
|
|
62
|
+
keys = keys.concat(batch);
|
|
63
|
+
startKey = batch[batchSize - 1];
|
|
64
|
+
}
|
|
65
|
+
return keys;
|
|
57
66
|
},
|
|
58
67
|
getNextKey: async function (key) {
|
|
59
|
-
const
|
|
60
|
-
return
|
|
68
|
+
const [nextKey] = await block.getKeysPaged({ prefix: key.slice(0, key_cache_1.PREFIX_LENGTH), pageSize: 1, startKey: key });
|
|
69
|
+
return nextKey;
|
|
61
70
|
},
|
|
62
71
|
};
|
|
63
72
|
};
|
package/lib/rpc/shared.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare const logger: import("pino").default.Logger<{
|
|
|
4
4
|
transport: {
|
|
5
5
|
target: string;
|
|
6
6
|
};
|
|
7
|
-
}
|
|
7
|
+
}>;
|
|
8
8
|
export declare class ResponseError extends Error {
|
|
9
9
|
code: number;
|
|
10
10
|
constructor(code: number, message: string);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HexString } from '@polkadot/util/types';
|
|
2
|
+
export declare const PREFIX_LENGTH = 66;
|
|
3
|
+
export default class KeyCache {
|
|
4
|
+
readonly ranges: Array<{
|
|
5
|
+
prefix: string;
|
|
6
|
+
keys: string[];
|
|
7
|
+
}>;
|
|
8
|
+
feed(keys: HexString[]): void;
|
|
9
|
+
next(startKey: HexString): Promise<HexString | undefined>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PREFIX_LENGTH = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
// 0x + 32 module + 32 method
|
|
9
|
+
exports.PREFIX_LENGTH = 66;
|
|
10
|
+
class KeyCache {
|
|
11
|
+
ranges = [];
|
|
12
|
+
feed(keys) {
|
|
13
|
+
const _keys = keys.filter((key) => key.length >= exports.PREFIX_LENGTH);
|
|
14
|
+
if (_keys.length === 0)
|
|
15
|
+
return;
|
|
16
|
+
const startKey = _keys[0].slice(exports.PREFIX_LENGTH);
|
|
17
|
+
const endKey = _keys[_keys.length - 1].slice(exports.PREFIX_LENGTH);
|
|
18
|
+
const grouped = lodash_1.default.groupBy(_keys, (key) => key.slice(0, exports.PREFIX_LENGTH));
|
|
19
|
+
for (const [prefix, keys] of Object.entries(grouped)) {
|
|
20
|
+
const ranges = this.ranges.filter((range) => range.prefix === prefix);
|
|
21
|
+
if (ranges.length === 0) {
|
|
22
|
+
// no existing range with prefix
|
|
23
|
+
this.ranges.push({ prefix, keys: keys.map((i) => i.slice(exports.PREFIX_LENGTH)) });
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
let merged = false;
|
|
27
|
+
for (const range of ranges) {
|
|
28
|
+
const startPosition = lodash_1.default.sortedIndex(range.keys, startKey);
|
|
29
|
+
if (startPosition >= 0 && range.keys[startPosition] === startKey) {
|
|
30
|
+
// found existing range with prefix
|
|
31
|
+
range.keys.splice(startPosition, keys.length, ...keys.map((i) => i.slice(exports.PREFIX_LENGTH)));
|
|
32
|
+
merged = true;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
const endPosition = lodash_1.default.sortedIndex(range.keys, endKey);
|
|
36
|
+
if (endPosition >= 0 && range.keys[endPosition] === endKey) {
|
|
37
|
+
// found existing range with prefix
|
|
38
|
+
range.keys.splice(0, endPosition + 1, ...keys.map((i) => i.slice(exports.PREFIX_LENGTH)));
|
|
39
|
+
merged = true;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// insert new prefix with range
|
|
44
|
+
if (!merged) {
|
|
45
|
+
this.ranges.push({ prefix, keys: keys.map((i) => i.slice(exports.PREFIX_LENGTH)) });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// TODO: merge ranges if they overlap
|
|
49
|
+
}
|
|
50
|
+
async next(startKey) {
|
|
51
|
+
if (startKey.length < exports.PREFIX_LENGTH)
|
|
52
|
+
return;
|
|
53
|
+
const prefix = startKey.slice(0, exports.PREFIX_LENGTH);
|
|
54
|
+
const key = startKey.slice(exports.PREFIX_LENGTH);
|
|
55
|
+
for (const range of this.ranges.filter((range) => range.prefix === prefix)) {
|
|
56
|
+
const index = lodash_1.default.sortedIndex(range.keys, key);
|
|
57
|
+
if (range.keys[index] !== key)
|
|
58
|
+
continue;
|
|
59
|
+
const nextKey = range.keys[index + 1];
|
|
60
|
+
if (nextKey) {
|
|
61
|
+
return [prefix, nextKey].join('');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.default = KeyCache;
|
package/lib/xcm/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export declare const logger: import("pino").default.Logger<{
|
|
|
4
4
|
transport: {
|
|
5
5
|
target: string;
|
|
6
6
|
};
|
|
7
|
-
}
|
|
7
|
+
}>;
|
|
8
8
|
export declare const connectVertical: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
|
|
9
9
|
export declare const connectParachains: (parachains: Blockchain[]) => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acala-network/chopsticks",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"author": "Bryan Chen <xlchen1291@gmail.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": "./chopsticks.js",
|
|
@@ -16,17 +16,17 @@
|
|
|
16
16
|
"dev:moonbeam": "cd ../..; ts-node-dev --transpile-only --inspect --notify=false packages/chopsticks/src/cli.ts -- --config=configs/moonbeam.yml"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@acala-network/chopsticks-executor": "0.6.
|
|
20
|
-
"@polkadot/api": "^10.
|
|
19
|
+
"@acala-network/chopsticks-executor": "0.6.6",
|
|
20
|
+
"@polkadot/api": "^10.7.2",
|
|
21
21
|
"axios": "^1.4.0",
|
|
22
22
|
"js-yaml": "^4.1.0",
|
|
23
23
|
"jsondiffpatch": "^0.4.1",
|
|
24
24
|
"lodash": "^4.17.21",
|
|
25
|
-
"pino": "^8.
|
|
25
|
+
"pino": "^8.14.1",
|
|
26
26
|
"pino-pretty": "^10.0.0",
|
|
27
27
|
"reflect-metadata": "^0.1.13",
|
|
28
28
|
"sqlite3": "^5.1.6",
|
|
29
|
-
"typeorm": "^0.3.
|
|
29
|
+
"typeorm": "^0.3.16",
|
|
30
30
|
"ws": "^8.13.0",
|
|
31
31
|
"yargs": "^17.7.2",
|
|
32
32
|
"zod": "^3.21.4"
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/js-yaml": "^4.0.5",
|
|
36
36
|
"@types/lodash": "^4.14.194",
|
|
37
|
-
"@types/node": "^
|
|
37
|
+
"@types/node": "^20.2.3",
|
|
38
38
|
"@types/ws": "^8.5.4",
|
|
39
39
|
"@types/yargs": "^17.0.24",
|
|
40
40
|
"ts-node": "^10.9.1",
|