@acala-network/chopsticks 0.6.4 → 0.6.5
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/storage-layer.js +35 -2
- 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
|
@@ -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/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.5",
|
|
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.5",
|
|
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",
|