@acala-network/chopsticks 0.2.3 → 0.3.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.
Files changed (67) hide show
  1. package/README.md +12 -1
  2. package/dist/api.d.ts +3 -2
  3. package/dist/api.js +15 -20
  4. package/dist/blockchain/block-builder.d.ts +5 -0
  5. package/dist/blockchain/block-builder.js +168 -0
  6. package/dist/blockchain/block.d.ts +6 -4
  7. package/dist/blockchain/block.js +22 -23
  8. package/dist/blockchain/head-state.d.ts +4 -2
  9. package/dist/blockchain/head-state.js +13 -7
  10. package/dist/blockchain/index.d.ts +13 -8
  11. package/dist/blockchain/index.js +44 -26
  12. package/dist/blockchain/inherent/index.d.ts +19 -0
  13. package/dist/blockchain/inherent/index.js +36 -0
  14. package/dist/blockchain/inherent/para-enter.d.ts +7 -0
  15. package/dist/blockchain/inherent/para-enter.js +33 -0
  16. package/dist/blockchain/inherent/parachain/babe-randomness.d.ts +7 -0
  17. package/dist/blockchain/inherent/parachain/babe-randomness.js +15 -0
  18. package/dist/blockchain/inherent/parachain/nimbus-author-inherent.d.ts +7 -0
  19. package/dist/blockchain/inherent/parachain/nimbus-author-inherent.js +15 -0
  20. package/dist/blockchain/inherent/parachain/validation-data.d.ts +25 -0
  21. package/dist/blockchain/{inherents.js → inherent/parachain/validation-data.js} +77 -46
  22. package/dist/blockchain/txpool.d.ts +17 -2
  23. package/dist/blockchain/txpool.js +11 -107
  24. package/dist/dry-run.d.ts +2 -0
  25. package/dist/dry-run.js +30 -0
  26. package/dist/executor.d.ts +17 -3
  27. package/dist/executor.js +43 -3
  28. package/dist/executor.test.js +16 -9
  29. package/dist/genesis-provider.d.ts +5 -0
  30. package/dist/genesis-provider.js +15 -3
  31. package/dist/index.d.ts +1 -18
  32. package/dist/index.js +79 -148
  33. package/dist/rpc/dev.js +39 -2
  34. package/dist/rpc/shared.d.ts +0 -4
  35. package/dist/rpc/substrate/author.d.ts +1 -1
  36. package/dist/rpc/substrate/author.js +7 -2
  37. package/dist/rpc/substrate/chain.js +2 -2
  38. package/dist/rpc/substrate/state.js +1 -1
  39. package/dist/rpc/substrate/system.js +3 -3
  40. package/dist/run-block.d.ts +2 -0
  41. package/dist/run-block.js +47 -0
  42. package/dist/schema/index.js +1 -1
  43. package/dist/server.d.ts +3 -3
  44. package/dist/server.js +26 -11
  45. package/dist/setup-with-server.d.ts +8 -0
  46. package/dist/setup-with-server.js +23 -0
  47. package/dist/setup.d.ts +10 -0
  48. package/dist/setup.js +67 -0
  49. package/dist/utils/decoder.d.ts +17 -0
  50. package/dist/utils/decoder.js +101 -0
  51. package/dist/utils/generate-html-diff.d.ts +4 -0
  52. package/dist/utils/generate-html-diff.js +20 -0
  53. package/dist/utils/index.d.ts +2 -0
  54. package/dist/utils/index.js +9 -1
  55. package/dist/utils/open-html.d.ts +1 -0
  56. package/dist/utils/open-html.js +9 -0
  57. package/dist/utils/proof.d.ts +10 -2
  58. package/dist/utils/proof.js +12 -8
  59. package/dist/utils/set-storage.d.ts +2 -1
  60. package/dist/utils/time-travel.d.ts +5 -0
  61. package/dist/utils/time-travel.js +64 -0
  62. package/dist/xcm/index.d.ts +3 -0
  63. package/dist/xcm/index.js +67 -0
  64. package/package.json +10 -7
  65. package/dist/bindings.d.ts +0 -2
  66. package/dist/bindings.js +0 -31
  67. package/dist/blockchain/inherents.d.ts +0 -24
package/dist/server.js CHANGED
@@ -35,19 +35,34 @@ const parseRequest = (request) => {
35
35
  return undefined;
36
36
  }
37
37
  };
38
- const createServer = (port, handler) => {
39
- logger.debug('Starting on port %d', port);
38
+ const createWS = async (port) => {
40
39
  const wss = new ws_1.WebSocketServer({ port, maxPayload: 1024 * 1024 * 100 });
41
- const promise = new Promise((resolve, reject) => {
40
+ const promise = new Promise((resolve) => {
42
41
  wss.on('listening', () => {
43
- logger.debug(wss.address(), 'Listening');
44
- resolve(wss.address().port);
42
+ resolve([wss, wss.address().port]);
45
43
  });
46
- wss.on('error', (err) => {
47
- logger.error(err, 'Error');
48
- reject(err);
44
+ wss.on('error', (_) => {
45
+ resolve([]);
49
46
  });
50
47
  });
48
+ return promise;
49
+ };
50
+ const createServer = async (handler, port) => {
51
+ let wss;
52
+ let listenPort;
53
+ for (let i = 0; i < 5; i++) {
54
+ const preferPort = (port || 0) + i;
55
+ logger.debug('Try starting on port %d', preferPort);
56
+ const [maybeWss, maybeListenPort] = await createWS(preferPort);
57
+ if (maybeWss && maybeListenPort) {
58
+ wss = maybeWss;
59
+ listenPort = maybeListenPort;
60
+ break;
61
+ }
62
+ }
63
+ if (!wss || !listenPort) {
64
+ throw new Error(`Failed to create WebsocketServer at port ${port}`);
65
+ }
51
66
  wss.on('connection', (ws) => {
52
67
  logger.debug('New connection');
53
68
  const send = (data) => {
@@ -131,10 +146,10 @@ const createServer = (port, handler) => {
131
146
  });
132
147
  });
133
148
  return {
134
- port: promise,
149
+ port: listenPort,
135
150
  close: () => new Promise((resolve, reject) => {
136
- wss.clients.forEach((socket) => socket.close());
137
- wss.close((err) => {
151
+ wss?.clients.forEach((socket) => socket.close());
152
+ wss?.close((err) => {
138
153
  if (err) {
139
154
  reject(err);
140
155
  }
@@ -0,0 +1,8 @@
1
+ import { Config } from './schema';
2
+ export declare const setupWithServer: (argv: Config) => Promise<{
3
+ close: () => Promise<void>;
4
+ listenPort: number;
5
+ chain: import("./blockchain").Blockchain;
6
+ api: import("./api").Api;
7
+ ws: import("@polkadot/rpc-provider/types").ProviderInterface;
8
+ }>;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupWithServer = void 0;
4
+ const server_1 = require("./server");
5
+ const rpc_1 = require("./rpc");
6
+ const shared_1 = require("./rpc/shared");
7
+ const setup_1 = require("./setup");
8
+ const setupWithServer = async (argv) => {
9
+ const context = await (0, setup_1.setup)(argv);
10
+ const port = argv.port || Number(process.env.PORT) || 8000;
11
+ if (argv.genesis) {
12
+ // mine 1st block when starting from genesis to set some mock validation data
13
+ await context.chain.newBlock();
14
+ }
15
+ const { close, port: listenPort } = await (0, server_1.createServer)((0, rpc_1.handler)(context), port);
16
+ shared_1.logger.info(`${await context.chain.api.getSystemChain()} RPC listening on port ${listenPort}`);
17
+ return {
18
+ ...context,
19
+ close,
20
+ listenPort,
21
+ };
22
+ };
23
+ exports.setupWithServer = setupWithServer;
@@ -0,0 +1,10 @@
1
+ import '@polkadot/types-codec';
2
+ import { ProviderInterface } from '@polkadot/rpc-provider/types';
3
+ import { Api } from './api';
4
+ import { Blockchain } from './blockchain';
5
+ import { Config } from './schema';
6
+ export declare const setup: (argv: Config) => Promise<{
7
+ chain: Blockchain;
8
+ api: Api;
9
+ ws: ProviderInterface;
10
+ }>;
package/dist/setup.js ADDED
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setup = void 0;
4
+ require("@polkadot/types-codec");
5
+ const api_1 = require("@polkadot/api");
6
+ const api_2 = require("./api");
7
+ const blockchain_1 = require("./blockchain");
8
+ const genesis_provider_1 = require("./genesis-provider");
9
+ const inherent_1 = require("./blockchain/inherent");
10
+ const logger_1 = require("./logger");
11
+ const import_storage_1 = require("./utils/import-storage");
12
+ const db_1 = require("./db");
13
+ const time_travel_1 = require("./utils/time-travel");
14
+ const setup = async (argv) => {
15
+ let provider;
16
+ if (argv.genesis) {
17
+ if (typeof argv.genesis === 'string') {
18
+ provider = await genesis_provider_1.GenesisProvider.fromUrl(argv.genesis);
19
+ }
20
+ else {
21
+ provider = new genesis_provider_1.GenesisProvider(argv.genesis);
22
+ }
23
+ }
24
+ else {
25
+ provider = new api_1.WsProvider(argv.endpoint);
26
+ }
27
+ const api = new api_2.Api(provider);
28
+ await api.isReady;
29
+ let blockHash;
30
+ if (argv.block == null) {
31
+ blockHash = await api.getBlockHash();
32
+ }
33
+ else if (Number.isInteger(+argv.block)) {
34
+ blockHash = await api.getBlockHash(Number(argv.block));
35
+ }
36
+ else {
37
+ blockHash = argv.block;
38
+ }
39
+ logger_1.defaultLogger.debug({ ...argv, blockHash }, 'Args');
40
+ let db;
41
+ if (argv.db) {
42
+ db = await (0, db_1.openDb)(argv.db);
43
+ }
44
+ const header = await api.getHeader(blockHash);
45
+ const inherents = new inherent_1.InherentProviders(new inherent_1.SetTimestamp(), [
46
+ new inherent_1.SetValidationData(),
47
+ new inherent_1.ParaInherentEnter(),
48
+ new inherent_1.SetNimbusAuthorInherent(),
49
+ new inherent_1.SetBabeRandomness(),
50
+ ]);
51
+ const chain = new blockchain_1.Blockchain({
52
+ api,
53
+ buildBlockMode: argv['build-block-mode'],
54
+ inherentProvider: inherents,
55
+ db,
56
+ header: {
57
+ hash: blockHash,
58
+ number: Number(header.number),
59
+ },
60
+ });
61
+ if (argv.timestamp)
62
+ await (0, time_travel_1.timeTravel)(chain, argv.timestamp);
63
+ await (0, import_storage_1.importStorage)(chain, argv['import-storage']);
64
+ await (0, import_storage_1.overrideWasm)(chain, argv['wasm-override']);
65
+ return { chain, api, ws: provider };
66
+ };
67
+ exports.setup = setup;
@@ -0,0 +1,17 @@
1
+ import '@polkadot/types-codec';
2
+ import { Block } from '../blockchain/block';
3
+ import { HexString } from '@polkadot/util/types';
4
+ import { StorageEntry } from '@polkadot/types/primitive/types';
5
+ import { StorageKey } from '@polkadot/types';
6
+ export declare const decodeKey: (block: Block, key: HexString) => Promise<{
7
+ storage?: StorageEntry | undefined;
8
+ decodedKey?: StorageKey<import("@polkadot/types-codec/types").AnyTuple> | undefined;
9
+ }>;
10
+ export declare const decodeKeyValue: (block: Block, key: HexString, value?: HexString | null) => Promise<{
11
+ [x: string]: `0x${string}` | null | undefined;
12
+ } | {
13
+ [x: string]: {
14
+ [x: string]: import("@polkadot/types-codec/types").AnyJson;
15
+ };
16
+ }>;
17
+ export declare const decodeStorageDiff: (block: Block, diff: [HexString, HexString | null][]) => Promise<({} | undefined)[]>;
@@ -0,0 +1,101 @@
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.decodeStorageDiff = exports.decodeKeyValue = exports.decodeKey = void 0;
7
+ require("@polkadot/types-codec");
8
+ const util_crypto_1 = require("@polkadot/util-crypto");
9
+ const jsondiffpatch_1 = require("jsondiffpatch");
10
+ const util_1 = require("@polkadot/util");
11
+ const lodash_1 = __importDefault(require("lodash"));
12
+ const diffPatcher = (0, jsondiffpatch_1.create)({
13
+ array: { detectMove: false },
14
+ textDiff: { minLength: Number.MAX_VALUE }, // skip text diff
15
+ });
16
+ const cache = {};
17
+ const getStorageEntry = async (block, key) => {
18
+ for (const [prefix, storageEntry] of Object.entries(cache)) {
19
+ if (key.startsWith(prefix))
20
+ return storageEntry;
21
+ }
22
+ const meta = await block.meta;
23
+ for (const module of Object.values(meta.query)) {
24
+ for (const storage of Object.values(module)) {
25
+ const keyPrefix = (0, util_1.u8aToHex)(storage.keyPrefix());
26
+ if (key.startsWith(keyPrefix)) {
27
+ cache[keyPrefix] = storage;
28
+ return storage;
29
+ }
30
+ }
31
+ }
32
+ throw new Error(`Cannot find key ${key}`);
33
+ };
34
+ const decodeKey = async (block, key) => {
35
+ const meta = await block.meta;
36
+ const storage = await getStorageEntry(block, key).catch(() => undefined);
37
+ const decodedKey = meta.registry.createType('StorageKey', key);
38
+ if (storage) {
39
+ decodedKey.setMeta(storage.meta);
40
+ return { storage, decodedKey };
41
+ }
42
+ return {};
43
+ };
44
+ exports.decodeKey = decodeKey;
45
+ const decodeKeyValue = async (block, key, value) => {
46
+ const meta = await block.meta;
47
+ const { storage, decodedKey } = await (0, exports.decodeKey)(block, key);
48
+ if (!storage || !decodedKey) {
49
+ return { [key]: value };
50
+ }
51
+ const decodeValue = () => {
52
+ if (!value)
53
+ return null;
54
+ if (storage.section === 'substrate' && storage.method === 'code') {
55
+ return `:code blake2_256 ${(0, util_crypto_1.blake2AsHex)(value, 256)} (${(0, util_1.hexToU8a)(value).length} bytes)`;
56
+ }
57
+ return meta.registry.createType(decodedKey.outputType, (0, util_1.hexToU8a)(value)).toHuman();
58
+ };
59
+ switch (decodedKey.args.length) {
60
+ case 2: {
61
+ return {
62
+ [storage.section]: {
63
+ [storage.method]: {
64
+ [decodedKey.args[0].toString()]: {
65
+ [decodedKey.args[1].toString()]: decodeValue(),
66
+ },
67
+ },
68
+ },
69
+ };
70
+ }
71
+ case 1: {
72
+ return {
73
+ [storage.section]: {
74
+ [storage.method]: {
75
+ [decodedKey.args[0].toString()]: decodeValue(),
76
+ },
77
+ },
78
+ };
79
+ }
80
+ default:
81
+ return {
82
+ [storage.section]: {
83
+ [storage.method]: decodeValue(),
84
+ },
85
+ };
86
+ }
87
+ };
88
+ exports.decodeKeyValue = decodeKeyValue;
89
+ const decodeStorageDiff = async (block, diff) => {
90
+ const parent = await block.parentBlock;
91
+ if (!parent)
92
+ throw new Error('Cannot find parent block');
93
+ const oldState = {};
94
+ const newState = {};
95
+ for (const [key, value] of diff) {
96
+ lodash_1.default.merge(oldState, await (0, exports.decodeKeyValue)(parent, key, (await parent.get(key))));
97
+ lodash_1.default.merge(newState, await (0, exports.decodeKeyValue)(block, key, value));
98
+ }
99
+ return [oldState, newState, diffPatcher.diff(oldState, newState)];
100
+ };
101
+ exports.decodeStorageDiff = decodeStorageDiff;
@@ -0,0 +1,4 @@
1
+ import { Block } from '../blockchain/block';
2
+ import { HexString } from '@polkadot/util/types';
3
+ export declare const generateHtmlDiff: (block: Block, diff: [HexString, HexString | null][]) => Promise<string>;
4
+ export declare const generateHtmlDiffPreviewFile: (block: Block, diff: [HexString, HexString | null][], filename: string) => Promise<string>;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateHtmlDiffPreviewFile = exports.generateHtmlDiff = void 0;
4
+ const decoder_1 = require("./decoder");
5
+ const node_fs_1 = require("node:fs");
6
+ const lodash_1 = require("lodash");
7
+ const generateHtmlDiff = async (block, diff) => {
8
+ const [left, _right, delta] = await (0, decoder_1.decodeStorageDiff)(block, diff);
9
+ const htmlTemplate = (0, node_fs_1.readFileSync)('./template/diff.html', 'utf-8');
10
+ return (0, lodash_1.template)(htmlTemplate)({ left: JSON.stringify(left), delta: JSON.stringify(delta) });
11
+ };
12
+ exports.generateHtmlDiff = generateHtmlDiff;
13
+ const generateHtmlDiffPreviewFile = async (block, diff, filename) => {
14
+ const html = await (0, exports.generateHtmlDiff)(block, diff);
15
+ (0, node_fs_1.mkdirSync)('./preview', { recursive: true });
16
+ const filePath = `./preview/${filename}.html`;
17
+ (0, node_fs_1.writeFileSync)(filePath, html);
18
+ return filePath;
19
+ };
20
+ exports.generateHtmlDiffPreviewFile = generateHtmlDiffPreviewFile;
@@ -1,7 +1,9 @@
1
1
  import { HexString } from '@polkadot/util/types';
2
2
  import { StorageKey } from '@polkadot/types';
3
+ import { Blockchain } from '../blockchain';
3
4
  export type GetKeys = (startKey?: string) => Promise<StorageKey<any>[]>;
4
5
  export type ProcessKey = (key: StorageKey<any>) => any;
5
6
  export declare function fetchKeys(getKeys: GetKeys, processKey: ProcessKey): Promise<void>;
6
7
  export declare function fetchKeysToArray(getKeys: GetKeys): Promise<StorageKey<any>[]>;
7
8
  export declare const compactHex: (value: Uint8Array) => HexString;
9
+ export declare const getParaId: (chain: Blockchain) => Promise<import("@polkadot/types").u32>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.compactHex = exports.fetchKeysToArray = exports.fetchKeys = void 0;
3
+ exports.getParaId = exports.compactHex = exports.fetchKeysToArray = exports.fetchKeys = void 0;
4
4
  const util_1 = require("@polkadot/util");
5
5
  async function fetchKeys(getKeys, processKey) {
6
6
  const processKeys = async (keys) => {
@@ -30,3 +30,11 @@ const compactHex = (value) => {
30
30
  return (0, util_1.u8aToHex)((0, util_1.compactStripLength)(value)[1]);
31
31
  };
32
32
  exports.compactHex = compactHex;
33
+ const getParaId = async (chain) => {
34
+ const meta = await chain.head.meta;
35
+ const raw = await chain.head.get((0, exports.compactHex)(meta.query.parachainInfo.parachainId()));
36
+ if (!raw)
37
+ throw new Error('Cannot find parachain id');
38
+ return meta.registry.createType('u32', (0, util_1.hexToU8a)(raw));
39
+ };
40
+ exports.getParaId = getParaId;
@@ -0,0 +1 @@
1
+ export declare const openHtml: (filePath: string) => void;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.openHtml = void 0;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const openHtml = (filePath) => {
6
+ const start = process.platform == 'darwin' ? 'open' : process.platform == 'win32' ? 'start' : 'xdg-open';
7
+ (0, node_child_process_1.execSync)(start + ' ' + filePath);
8
+ };
9
+ exports.openHtml = openHtml;
@@ -1,7 +1,15 @@
1
- import { HexString } from '@polkadot/util/types';
1
+ import { HrmpChannelId } from '@polkadot/types/interfaces';
2
2
  import { u32 } from '@polkadot/types';
3
- export declare const WELL_KNOWN_KEYS: Record<string, HexString>;
3
+ export declare const WELL_KNOWN_KEYS: {
4
+ EPOCH_INDEX: `0x${string}`;
5
+ CURRENT_BLOCK_RANDOMNESS: `0x${string}`;
6
+ ONE_EPOCH_AGO_RANDOMNESS: `0x${string}`;
7
+ TWO_EPOCHS_AGO_RANDOMNESS: `0x${string}`;
8
+ CURRENT_SLOT: `0x${string}`;
9
+ ACTIVE_CONFIG: `0x${string}`;
10
+ };
4
11
  export declare const dmqMqcHead: (paraId: u32) => `0x${string}`;
5
12
  export declare const upgradeGoAheadSignal: (paraId: u32) => `0x${string}`;
6
13
  export declare const hrmpIngressChannelIndex: (paraId: u32) => `0x${string}`;
7
14
  export declare const hrmpEgressChannelIndex: (paraId: u32) => `0x${string}`;
15
+ export declare const hrmpChannels: (channelId: HrmpChannelId) => `0x${string}`;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hrmpEgressChannelIndex = exports.hrmpIngressChannelIndex = exports.upgradeGoAheadSignal = exports.dmqMqcHead = exports.WELL_KNOWN_KEYS = void 0;
3
+ exports.hrmpChannels = exports.hrmpEgressChannelIndex = exports.hrmpIngressChannelIndex = exports.upgradeGoAheadSignal = exports.dmqMqcHead = exports.WELL_KNOWN_KEYS = void 0;
4
4
  const util_1 = require("@polkadot/util");
5
5
  const util_crypto_1 = require("@polkadot/util-crypto");
6
6
  exports.WELL_KNOWN_KEYS = {
@@ -11,27 +11,31 @@ exports.WELL_KNOWN_KEYS = {
11
11
  CURRENT_SLOT: '0x1cb6f36e027abb2091cfb5110ab5087f06155b3cd9a8c9e5e9a23fd5dc13a5ed',
12
12
  ACTIVE_CONFIG: '0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385',
13
13
  };
14
- const prefixWithParaId = (prefix, paraId) => {
15
- const id = paraId.toU8a();
16
- return (0, util_1.u8aToHex)((0, util_1.u8aConcat)((0, util_1.hexToU8a)(prefix), (0, util_crypto_1.xxhashAsU8a)(id, 64), id));
14
+ const hash = (prefix, suffix) => {
15
+ return (0, util_1.u8aToHex)((0, util_1.u8aConcat)((0, util_1.hexToU8a)(prefix), (0, util_crypto_1.xxhashAsU8a)(suffix, 64), suffix));
17
16
  };
18
17
  const dmqMqcHead = (paraId) => {
19
18
  const prefix = '0x63f78c98723ddc9073523ef3beefda0c4d7fefc408aac59dbfe80a72ac8e3ce5';
20
- return prefixWithParaId(prefix, paraId);
19
+ return hash(prefix, paraId.toU8a());
21
20
  };
22
21
  exports.dmqMqcHead = dmqMqcHead;
23
22
  const upgradeGoAheadSignal = (paraId) => {
24
23
  const prefix = '0xcd710b30bd2eab0352ddcc26417aa1949e94c040f5e73d9b7addd6cb603d15d3';
25
- return prefixWithParaId(prefix, paraId);
24
+ return hash(prefix, paraId.toU8a());
26
25
  };
27
26
  exports.upgradeGoAheadSignal = upgradeGoAheadSignal;
28
27
  const hrmpIngressChannelIndex = (paraId) => {
29
28
  const prefix = '0x6a0da05ca59913bc38a8630590f2627c1d3719f5b0b12c7105c073c507445948';
30
- return prefixWithParaId(prefix, paraId);
29
+ return hash(prefix, paraId.toU8a());
31
30
  };
32
31
  exports.hrmpIngressChannelIndex = hrmpIngressChannelIndex;
33
32
  const hrmpEgressChannelIndex = (paraId) => {
34
33
  const prefix = '0x6a0da05ca59913bc38a8630590f2627cf12b746dcf32e843354583c9702cc020';
35
- return prefixWithParaId(prefix, paraId);
34
+ return hash(prefix, paraId.toU8a());
36
35
  };
37
36
  exports.hrmpEgressChannelIndex = hrmpEgressChannelIndex;
37
+ const hrmpChannels = (channelId) => {
38
+ const prefix = '0x6a0da05ca59913bc38a8630590f2627cb6604cff828a6e3f579ca6c59ace013d';
39
+ return hash(prefix, channelId.toU8a());
40
+ };
41
+ exports.hrmpChannels = hrmpChannels;
@@ -1,6 +1,7 @@
1
+ import { HexString } from '@polkadot/util/types';
1
2
  import { Blockchain } from '../blockchain';
2
3
  type RawStorageValues = [string, string | null][];
3
4
  type StorageConfig = Record<string, Record<string, any>>;
4
5
  export type StorageValues = RawStorageValues | StorageConfig;
5
- export declare const setStorage: (chain: Blockchain, storage: StorageValues, blockHash?: string) => Promise<string>;
6
+ export declare const setStorage: (chain: Blockchain, storage: StorageValues, blockHash?: HexString) => Promise<HexString>;
6
7
  export {};
@@ -0,0 +1,5 @@
1
+ import { Blockchain } from '../blockchain';
2
+ export declare const getCurrentSlot: (chain: Blockchain) => Promise<number>;
3
+ export declare const getCurrentTimestamp: (chain: Blockchain) => Promise<number>;
4
+ export declare const getSlotDuration: (chain: Blockchain) => Promise<number>;
5
+ export declare const timeTravel: (chain: Blockchain, timestamp: number) => Promise<void>;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.timeTravel = exports.getSlotDuration = exports.getCurrentTimestamp = exports.getCurrentSlot = void 0;
4
+ const util_1 = require("@polkadot/util");
5
+ const _1 = require(".");
6
+ const executor_1 = require("../executor");
7
+ const set_storage_1 = require("./set-storage");
8
+ const getCurrentSlot = async (chain) => {
9
+ const meta = await chain.head.meta;
10
+ const slotRaw = meta.consts.babe
11
+ ? await chain.head.get((0, _1.compactHex)(meta.query.babe.currentSlot()))
12
+ : await chain.head.get((0, _1.compactHex)(meta.query.aura.currentSlot()));
13
+ if (!slotRaw)
14
+ throw new Error('Cannot find current slot');
15
+ return meta.registry.createType('Slot', (0, util_1.hexToU8a)(slotRaw)).toNumber();
16
+ };
17
+ exports.getCurrentSlot = getCurrentSlot;
18
+ const getCurrentTimestamp = async (chain) => {
19
+ const meta = await chain.head.meta;
20
+ const currentTimestampRaw = (await chain.head.get((0, _1.compactHex)(meta.query.timestamp.now()))) || '0x';
21
+ return meta.registry.createType('u64', (0, util_1.hexToU8a)(currentTimestampRaw)).toNumber();
22
+ };
23
+ exports.getCurrentTimestamp = getCurrentTimestamp;
24
+ const getSlotDuration = async (chain) => {
25
+ const meta = await chain.head.meta;
26
+ return meta.consts.babe
27
+ ? meta.consts.babe.expectedBlockTime.toNumber()
28
+ : meta.query.aura
29
+ ? (0, executor_1.getAuraSlotDuration)(await chain.head.wasm, meta.registry)
30
+ : 12_000;
31
+ };
32
+ exports.getSlotDuration = getSlotDuration;
33
+ const timeTravel = async (chain, timestamp) => {
34
+ const meta = await chain.head.meta;
35
+ const slotDuration = await (0, exports.getSlotDuration)(chain);
36
+ const newSlot = Math.floor(timestamp / slotDuration);
37
+ // new timestamp
38
+ const storage = [
39
+ [(0, _1.compactHex)(meta.query.timestamp.now()), (0, util_1.u8aToHex)(meta.registry.createType('u64', timestamp).toU8a())],
40
+ ];
41
+ if (meta.consts.babe) {
42
+ // new slot
43
+ storage.push([
44
+ (0, _1.compactHex)(meta.query.babe.currentSlot()),
45
+ (0, util_1.u8aToHex)(meta.registry.createType('Slot', newSlot).toU8a()),
46
+ ]);
47
+ // new epoch
48
+ const epochDuration = meta.consts.babe.epochDuration.toNumber();
49
+ const newEpoch = Math.floor(timestamp / epochDuration);
50
+ storage.push([
51
+ (0, _1.compactHex)(meta.query.babe.epochIndex()),
52
+ (0, util_1.u8aToHex)(meta.registry.createType('u64', newEpoch).toU8a()),
53
+ ]);
54
+ }
55
+ else if (meta.query.aura) {
56
+ // new slot
57
+ storage.push([
58
+ (0, _1.compactHex)(meta.query.aura.currentSlot()),
59
+ (0, util_1.u8aToHex)(meta.registry.createType('Slot', newSlot).toU8a()),
60
+ ]);
61
+ }
62
+ await (0, set_storage_1.setStorage)(chain, storage);
63
+ };
64
+ exports.timeTravel = timeTravel;
@@ -0,0 +1,3 @@
1
+ import { Blockchain } from '../blockchain';
2
+ export declare const connectDownward: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
3
+ export declare const connectParachains: (parachains: Blockchain[]) => Promise<void>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectParachains = exports.connectDownward = void 0;
4
+ const util_1 = require("@polkadot/util");
5
+ const utils_1 = require("../utils");
6
+ const logger_1 = require("../logger");
7
+ const set_storage_1 = require("../utils/set-storage");
8
+ const logger = logger_1.defaultLogger.child({ name: 'xcm' });
9
+ const connectDownward = async (relaychain, parachain) => {
10
+ const meta = await relaychain.head.meta;
11
+ const paraId = await (0, utils_1.getParaId)(parachain);
12
+ const downwardMessageQueuesKey = (0, utils_1.compactHex)(meta.query.dmp.downwardMessageQueues(paraId));
13
+ await relaychain.headState.subscribeStorage([downwardMessageQueuesKey], async (head, pairs) => {
14
+ const value = pairs[0][1];
15
+ if (!value)
16
+ return;
17
+ const meta = await relaychain.head.meta;
18
+ const downwardMessageQueuesKey = (0, utils_1.compactHex)(meta.query.dmp.downwardMessageQueues(paraId));
19
+ // clear relaychain message queue
20
+ await (0, set_storage_1.setStorage)(relaychain, [[downwardMessageQueuesKey, null]], head.hash);
21
+ const downwardMessages = meta.registry
22
+ .createType('Vec<PolkadotCorePrimitivesInboundDownwardMessage>', (0, util_1.hexToU8a)(value))
23
+ .toJSON();
24
+ logger.debug({ downwardMessages }, 'downward_message');
25
+ await parachain.newBlock({ inherent: { downwardMessages } });
26
+ });
27
+ logger.info(`Connected relaychain '${await relaychain.api.getSystemChain()}' with parachain '${await parachain.api.getSystemChain()}'`);
28
+ };
29
+ exports.connectDownward = connectDownward;
30
+ const connectParachains = async (parachains) => {
31
+ const list = {};
32
+ for (const chain of parachains) {
33
+ const paraId = await (0, utils_1.getParaId)(chain);
34
+ list[paraId.toNumber()] = chain;
35
+ }
36
+ await connectHorizontal(list);
37
+ logger.info('Parachains connected');
38
+ };
39
+ exports.connectParachains = connectParachains;
40
+ const connectHorizontal = async (parachains) => {
41
+ for (const [id, chain] of Object.entries(parachains)) {
42
+ const meta = await chain.head.meta;
43
+ const hrmpOutboundMessagesKey = (0, utils_1.compactHex)(meta.query.parachainSystem.hrmpOutboundMessages());
44
+ await chain.headState.subscribeStorage([hrmpOutboundMessagesKey], async (head, pairs) => {
45
+ const value = pairs[0][1];
46
+ if (!value)
47
+ return;
48
+ const meta = await chain.head.meta;
49
+ const hrmpOutboundMessagesKey = (0, utils_1.compactHex)(meta.query.parachainSystem.hrmpOutboundMessages());
50
+ // clear sender message queue
51
+ await (0, set_storage_1.setStorage)(chain, [[hrmpOutboundMessagesKey, null]], head.hash);
52
+ const outboundHrmpMessage = meta.registry
53
+ .createType('Vec<PolkadotCorePrimitivesOutboundHrmpMessage>', (0, util_1.hexToU8a)(value))
54
+ .toJSON();
55
+ logger.info({ outboundHrmpMessage }, 'outboundHrmpMessage');
56
+ for (const { recipient, data } of outboundHrmpMessage) {
57
+ const horizontalMessages = {
58
+ [Number(id)]: [{ sentAt: chain.head.number, data }],
59
+ };
60
+ const receiver = parachains[recipient];
61
+ if (receiver) {
62
+ await receiver.newBlock({ inherent: { horizontalMessages } });
63
+ }
64
+ }
65
+ });
66
+ }
67
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Bryan Chen <xlchen1291@gmail.com>",
@@ -24,10 +24,12 @@
24
24
  "test:dev": "LOG_LEVEL=trace vitest --inspect",
25
25
  "dev": "LOG_LEVEL=trace ts-node-dev --transpile-only --inspect --notify=false src/index.ts -- dev --config=configs/dev.yml",
26
26
  "dev:karura": "ts-node-dev --transpile-only --inspect --notify=false src/index.ts -- dev --config=configs/karura.yml",
27
- "dev:acala": "ts-node-dev --transpile-only --inspect --notify=false src/index.ts -- dev --config=configs/acala.yml"
27
+ "dev:acala": "ts-node-dev --transpile-only --inspect --notify=false src/index.ts -- dev --config=configs/acala.yml",
28
+ "dev:moonriver": "ts-node-dev --transpile-only --inspect --notify=false src/index.ts -- dev --config=configs/moonriver.yml",
29
+ "dev:moonbeam": "ts-node-dev --transpile-only --inspect --notify=false src/index.ts -- dev --config=configs/moonbeam.yml"
28
30
  },
29
31
  "dependencies": {
30
- "@acala-network/chopsticks-executor": "0.2.3",
32
+ "@acala-network/chopsticks-executor": "0.3.0",
31
33
  "@polkadot/api": "^9.10.1",
32
34
  "@polkadot/rpc-provider": "^9.10.1",
33
35
  "@polkadot/types": "^9.10.1",
@@ -35,8 +37,9 @@
35
37
  "@polkadot/types-known": "^9.10.1",
36
38
  "@polkadot/util": "^10.2.1",
37
39
  "@polkadot/util-crypto": "^10.2.1",
38
- "axios": "^1.2.1",
40
+ "axios": "^1.2.2",
39
41
  "js-yaml": "^4.1.0",
42
+ "jsondiffpatch": "^0.4.1",
40
43
  "lodash": "^4.17.21",
41
44
  "pino": "^8.7.0",
42
45
  "pino-pretty": "^9.1.1",
@@ -51,13 +54,13 @@
51
54
  "devDependencies": {
52
55
  "@types/js-yaml": "^4.0.5",
53
56
  "@types/lodash": "^4.14.191",
54
- "@types/node": "^18.11.10",
57
+ "@types/node": "^18.11.18",
55
58
  "@types/rimraf": "^3",
56
59
  "@types/ws": "^8.5.3",
57
- "@types/yargs": "^17.0.15",
60
+ "@types/yargs": "^17.0.18",
58
61
  "@typescript-eslint/eslint-plugin": "^5.45.0",
59
62
  "@typescript-eslint/parser": "^5.45.0",
60
- "eslint": "^8.29.0",
63
+ "eslint": "^8.31.0",
61
64
  "eslint-config-prettier": "^8.5.0",
62
65
  "eslint-plugin-import": "^2.26.0",
63
66
  "eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
@@ -1,2 +0,0 @@
1
- import { Blockchain } from './blockchain';
2
- export declare const setupBindings: (chain: Blockchain) => void;