@acala-network/chopsticks 0.3.1 → 0.3.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/README.md CHANGED
@@ -31,7 +31,8 @@ Make sure you have setup Rust environment (>= 1.64).
31
31
  - Use option `--html` to generate storage diff preview (add `--open` to automatically open file)
32
32
 
33
33
  - Dry run extrinsic, same as `run-block`, example:
34
- - `yarn start dry-run --config=configs/mandala.yml --html --open --extrinsic 0x51028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01a4143d076116f80a4074ed7acc90f9e1f9e2db54603900be53145a6ef5faa333f2614e687a06a9c886a909d77f3115b1a9d989afdc9fd73e5dca941bc690ae8a0000000a00008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a481b000000a1edccce1bc2d3`
34
+ - `yarn start dry-run --config=configs/mandala.yml --html --open --extrinsic=0x39028400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01183abac17ff331f8b65dbeddd27f014dedd892020cfdc6c40b574f6930f8cf391bde95997ae2edc5b1192a4036ea97804956c4b5497175c8d68b630301685889450200000a00008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480284d717`
35
+ - Dry run call `yarn start dry-run --config=configs/mandala.yml --html --open --extrinsic=0xff00000080969800 --address=5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY --at=0x5f660b32489966cc707ecde831864aeecf9092c4983e75f9880313e9158d62b9`
35
36
 
36
37
  - Run a test node
37
38
  - `yarn start dev --endpoint=wss://acala-rpc-2.aca-api.network/ws`
@@ -63,7 +64,7 @@ Make sure you have setup Rust environment (>= 1.64).
63
64
  - Edit configs/kusama.yml if needed. (e.g. update the block number)
64
65
  - `yarn start dev --config=configs/kusama.yml`
65
66
 
66
- - Setup XCM multichain (UpwardMessages not yet supported)
67
+ - Setup XCM multichain
67
68
  **_NOTE:_** You can also connect multiple parachains without a relaychain
68
69
  ```bash
69
70
  yarn start xcm --relaychain=configs/kusama.yml --parachain=configs/karura.yml --parachain=configs/statemine.yml
@@ -1,5 +1,8 @@
1
1
  import { Block, TaskCallResponse } from './block';
2
2
  import { HexString } from '@polkadot/util/types';
3
3
  export declare const buildBlock: (head: Block, inherents: HexString[], extrinsics: HexString[]) => Promise<[Block, HexString[]]>;
4
- export declare const dryRunExtrinsic: (head: Block, inherents: HexString[], extrinsic: HexString) => Promise<TaskCallResponse>;
4
+ export declare const dryRunExtrinsic: (head: Block, inherents: HexString[], extrinsic: HexString | {
5
+ call: HexString;
6
+ address: string;
7
+ }) => Promise<TaskCallResponse>;
5
8
  export declare const dryRunInherents: (head: Block, inherents: HexString[]) => Promise<[HexString, HexString | null][]>;
@@ -94,14 +94,14 @@ const initNewBlock = async (head, header, inherents) => {
94
94
  // initialize block
95
95
  const { storageDiff } = await newBlock.call('Core_initialize_block', header.toHex());
96
96
  newBlock.pushStorageLayer().setAll(storageDiff);
97
- logger.trace((0, logger_1.truncateStorageDiff)(storageDiff), 'Initialize block');
97
+ logger.trace((0, logger_1.truncate)(storageDiff), 'Initialize block');
98
98
  }
99
99
  // apply inherents
100
100
  for (const extrinsic of inherents) {
101
101
  try {
102
102
  const { storageDiff } = await newBlock.call('BlockBuilder_apply_extrinsic', extrinsic);
103
103
  newBlock.pushStorageLayer().setAll(storageDiff);
104
- logger.trace((0, logger_1.truncateStorageDiff)(storageDiff), 'Applied inherent');
104
+ logger.trace((0, logger_1.truncate)(storageDiff), 'Applied inherent');
105
105
  }
106
106
  catch (e) {
107
107
  logger.warn('Failed to apply inherents %o %s', e, e);
@@ -125,7 +125,7 @@ const buildBlock = async (head, inherents, extrinsics) => {
125
125
  try {
126
126
  const { storageDiff } = await newBlock.call('BlockBuilder_apply_extrinsic', extrinsic);
127
127
  newBlock.pushStorageLayer().setAll(storageDiff);
128
- logger.trace((0, logger_1.truncateStorageDiff)(storageDiff), 'Applied extrinsic');
128
+ logger.trace((0, logger_1.truncate)(storageDiff), 'Applied extrinsic');
129
129
  }
130
130
  catch (e) {
131
131
  logger.info('Failed to apply extrinsic %o %s', e, e);
@@ -136,7 +136,7 @@ const buildBlock = async (head, inherents, extrinsics) => {
136
136
  // finalize block
137
137
  const { storageDiff } = await newBlock.call('BlockBuilder_finalize_block', '0x');
138
138
  newBlock.pushStorageLayer().setAll(storageDiff);
139
- logger.trace((0, logger_1.truncateStorageDiff)(storageDiff), 'Finalize block');
139
+ logger.trace((0, logger_1.truncate)(storageDiff), 'Finalize block');
140
140
  }
141
141
  const blockData = registry.createType('Block', {
142
142
  header,
@@ -155,8 +155,32 @@ const buildBlock = async (head, inherents, extrinsics) => {
155
155
  };
156
156
  exports.buildBlock = buildBlock;
157
157
  const dryRunExtrinsic = async (head, inherents, extrinsic) => {
158
+ const registry = await head.registry;
158
159
  const header = await newHeader(head);
159
160
  const newBlock = await initNewBlock(head, header, inherents);
161
+ if (typeof extrinsic !== 'string') {
162
+ if (!head.chain.mockSignatureHost) {
163
+ throw new Error('Cannot fake signature because mock signature host is not enabled. Start chain with `mockSignatureHost: true`');
164
+ }
165
+ const meta = await head.meta;
166
+ const call = registry.createType('Call', (0, util_1.hexToU8a)(extrinsic.call));
167
+ const generic = registry.createType('GenericExtrinsic', call);
168
+ const accountRaw = await head.get((0, utils_1.compactHex)(meta.query.system.account(extrinsic.address)));
169
+ const account = registry.createType('AccountInfo', (0, util_1.hexToU8a)(accountRaw));
170
+ generic.signFake(extrinsic.address, {
171
+ blockHash: head.hash,
172
+ genesisHash: head.hash,
173
+ runtimeVersion: await head.runtimeVersion,
174
+ nonce: account.nonce,
175
+ });
176
+ const mockSignature = new Uint8Array(64);
177
+ mockSignature.fill(0xcd);
178
+ mockSignature.set([0xde, 0xad, 0xbe, 0xef]);
179
+ generic.signature.set(mockSignature);
180
+ logger_1.defaultLogger.info({ call: call.toHuman() }, 'dry_run_call');
181
+ return newBlock.call('BlockBuilder_apply_extrinsic', generic.toHex());
182
+ }
183
+ logger_1.defaultLogger.info({ call: registry.createType('GenericExtrinsic', (0, util_1.hexToU8a)(extrinsic)).toHuman() }, 'dry_run_extrinsic');
160
184
  return newBlock.call('BlockBuilder_apply_extrinsic', extrinsic);
161
185
  };
162
186
  exports.dryRunExtrinsic = dryRunExtrinsic;
@@ -20,6 +20,7 @@ export interface Options {
20
20
  }
21
21
  export declare class Blockchain {
22
22
  #private;
23
+ readonly uid: string;
23
24
  readonly api: Api;
24
25
  readonly db: DataSource | undefined;
25
26
  readonly mockSignatureHost: boolean;
@@ -34,7 +35,10 @@ export declare class Blockchain {
34
35
  setHead(block: Block): Promise<void>;
35
36
  submitExtrinsic(extrinsic: HexString): Promise<HexString>;
36
37
  newBlock(params?: BuildBlockParams): Promise<Block>;
37
- dryRunExtrinsic(extrinsic: HexString): Promise<{
38
+ dryRunExtrinsic(extrinsic: HexString | {
39
+ call: HexString;
40
+ address: string;
41
+ }, at?: HexString): Promise<{
38
42
  outcome: ApplyExtrinsicResult;
39
43
  storageDiff: [HexString, HexString | null][];
40
44
  }>;
@@ -10,6 +10,7 @@ const logger_1 = require("../logger");
10
10
  const block_builder_1 = require("./block-builder");
11
11
  const logger = logger_1.defaultLogger.child({ name: 'blockchain' });
12
12
  class Blockchain {
13
+ uid = Math.random().toString(36).substring(2);
13
14
  api;
14
15
  db;
15
16
  mockSignatureHost;
@@ -118,9 +119,12 @@ class Blockchain {
118
119
  await this.#txpool.buildBlock(params);
119
120
  return this.#head;
120
121
  }
121
- async dryRunExtrinsic(extrinsic) {
122
+ async dryRunExtrinsic(extrinsic, at) {
122
123
  await this.api.isReady;
123
- const head = this.head;
124
+ const head = at ? await this.getBlock(at) : this.head;
125
+ if (!head) {
126
+ throw new Error(`Cannot find block ${at}`);
127
+ }
124
128
  const registry = await head.registry;
125
129
  const inherents = await this.#inherentProvider.createInherents(head);
126
130
  const { result, storageDiff } = await (0, block_builder_1.dryRunExtrinsic)(head, inherents, extrinsic);
package/dist/dry-run.js CHANGED
@@ -3,15 +3,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dryRun = void 0;
4
4
  const util_crypto_1 = require("@polkadot/util-crypto");
5
5
  const node_fs_1 = require("node:fs");
6
+ const logger_1 = require("./logger");
6
7
  const generate_html_diff_1 = require("./utils/generate-html-diff");
7
8
  const open_html_1 = require("./utils/open-html");
8
9
  const setup_1 = require("./setup");
9
10
  const dryRun = async (argv) => {
10
11
  const context = await (0, setup_1.setup)(argv);
11
- const { outcome, storageDiff } = await context.chain.dryRunExtrinsic(argv['extrinsic']);
12
+ const input = argv['address'] ? { call: argv['extrinsic'], address: argv['address'] } : argv['extrinsic'];
13
+ const { outcome, storageDiff } = await context.chain.dryRunExtrinsic(input, argv['at']);
12
14
  if (outcome.isErr) {
13
15
  throw new Error(outcome.asErr.toString());
14
16
  }
17
+ else {
18
+ logger_1.defaultLogger.info(outcome.toHuman(), 'dry_run_outcome');
19
+ }
15
20
  if (argv['html']) {
16
21
  const filePath = await (0, generate_html_diff_1.generateHtmlDiffPreviewFile)(context.chain.head, storageDiff, (0, util_crypto_1.blake2AsHex)(argv['extrinsic'], 256));
17
22
  console.log(`Generated preview ${filePath}`);
package/dist/executor.js CHANGED
@@ -38,10 +38,10 @@ const createProof = async (trieRootHash, nodes, entries) => {
38
38
  };
39
39
  exports.createProof = createProof;
40
40
  const runTask = async (task, callback = exports.emptyTaskHandler) => {
41
- logger.trace({ task: { ...task, wasm: (0, logger_1.truncate)(task.wasm) } }, 'taskRun');
41
+ logger.trace((0, logger_1.truncate)(task), 'taskRun');
42
42
  const response = await (0, chopsticks_executor_1.run_task)(task, callback);
43
43
  if (response.Call) {
44
- logger.trace({ result: (0, logger_1.truncate)(response.Call.result), storageDiff: (0, logger_1.truncateStorageDiff)(response.Call.storageDiff) }, 'taskResponse');
44
+ logger.trace((0, logger_1.truncate)(response.Call), 'taskResponse');
45
45
  }
46
46
  else {
47
47
  logger.trace({ response }, 'taskResponse');
@@ -58,7 +58,7 @@ const taskHandler = (block) => {
58
58
  return block.getKeysPaged({ prefix: key, pageSize: 1000, startKey: key });
59
59
  },
60
60
  getNextKey: async function (key) {
61
- const keys = await block.getKeysPaged({ prefix: key, pageSize: 1, startKey: key });
61
+ const keys = await block.getKeysPaged({ prefix: '0x', pageSize: 1, startKey: key });
62
62
  return keys[0];
63
63
  },
64
64
  };
package/dist/index.js CHANGED
@@ -71,10 +71,18 @@ const defaultOptions = {
71
71
  .command('dry-run', 'Dry run an extrinsic', (yargs) => yargs.options({
72
72
  ...defaultOptions,
73
73
  extrinsic: {
74
- desc: 'Extrinsic to dry run',
74
+ desc: 'Extrinsic or call to dry run. If you pass call here then address is required to fake signature',
75
75
  string: true,
76
76
  required: true,
77
77
  },
78
+ address: {
79
+ desc: 'Address to fake sign extrinsic',
80
+ string: true,
81
+ },
82
+ at: {
83
+ desc: 'Block hash to dry run',
84
+ string: true,
85
+ },
78
86
  'output-path': {
79
87
  desc: 'File path to print output',
80
88
  string: true,
@@ -106,6 +114,10 @@ const defaultOptions = {
106
114
  desc: 'Mock signature host so any signature starts with 0xdeadbeef and filled by 0xcd is considered valid',
107
115
  boolean: true,
108
116
  },
117
+ 'allow-unresolved-imports': {
118
+ desc: 'Allow wasm unresolved imports',
119
+ boolean: true,
120
+ },
109
121
  }), async (argv) => {
110
122
  await (0, setup_with_server_1.setupWithServer)(processArgv(argv));
111
123
  })
@@ -150,7 +162,7 @@ const defaultOptions = {
150
162
  if (argv.relaychain) {
151
163
  const { chain: relaychain } = await (0, setup_with_server_1.setupWithServer)(processConfig(argv.relaychain));
152
164
  for (const parachain of parachains) {
153
- await (0, xcm_1.connectDownward)(relaychain, parachain);
165
+ await (0, xcm_1.connectVertical)(relaychain, parachain);
154
166
  }
155
167
  }
156
168
  })
package/dist/logger.d.ts CHANGED
@@ -1,9 +1,7 @@
1
- import { HexString } from '@polkadot/util/types';
2
1
  export declare const defaultLogger: import("pino").Logger<{
3
2
  level: string;
4
3
  transport: {
5
4
  target: string;
6
5
  };
7
6
  }>;
8
- export declare const truncate: (str: string | null) => string | null;
9
- export declare const truncateStorageDiff: (diff: [HexString, HexString | null][]) => [HexString, string | null][];
7
+ export declare const truncate: (val: any) => any;
package/dist/logger.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.truncateStorageDiff = exports.truncate = exports.defaultLogger = void 0;
6
+ exports.truncate = exports.defaultLogger = void 0;
7
7
  const pino_1 = __importDefault(require("pino"));
8
8
  exports.defaultLogger = (0, pino_1.default)({
9
9
  level: process.env.LOG_LEVEL || 'info',
@@ -11,19 +11,25 @@ exports.defaultLogger = (0, pino_1.default)({
11
11
  target: 'pino-pretty',
12
12
  },
13
13
  });
14
- const truncate = (str) => {
15
- if (str == null) {
16
- return str;
14
+ const truncate = (val) => {
15
+ if (val == null) {
16
+ return val;
17
17
  }
18
- if (str.length > 66) {
19
- return str.slice(0, 34) + '' + str.slice(-32);
20
- }
21
- else {
22
- return str;
18
+ switch (typeof val) {
19
+ case 'string':
20
+ if (val.length > 66) {
21
+ return val.slice(0, 34) + '…' + val.slice(-32);
22
+ }
23
+ else {
24
+ return val;
25
+ }
26
+ case 'object':
27
+ if (Array.isArray(val)) {
28
+ return val.map(exports.truncate);
29
+ }
30
+ return Object.fromEntries(Object.entries(val).map(([k, v]) => [k, (0, exports.truncate)(v)]));
31
+ default:
32
+ return val;
23
33
  }
24
34
  };
25
35
  exports.truncate = truncate;
26
- const truncateStorageDiff = (diff) => {
27
- return diff.map(([key, value]) => [key, (0, exports.truncate)(value)]);
28
- };
29
- exports.truncateStorageDiff = truncateStorageDiff;
package/dist/rpc/dev.js CHANGED
@@ -66,5 +66,20 @@ const handlers = {
66
66
  delta,
67
67
  };
68
68
  },
69
+ dev_setHead: async (context, [hashOrNumber]) => {
70
+ let block;
71
+ if (typeof hashOrNumber === 'number') {
72
+ const blockNumber = hashOrNumber > 0 ? hashOrNumber : context.chain.head.number + hashOrNumber;
73
+ block = await context.chain.getBlockAt(blockNumber);
74
+ }
75
+ else {
76
+ block = await context.chain.getBlock(hashOrNumber);
77
+ }
78
+ if (!block) {
79
+ throw new shared_1.ResponseError(1, `Block not found ${hashOrNumber}`);
80
+ }
81
+ await context.chain.setHead(block);
82
+ return block.hash;
83
+ },
69
84
  };
70
85
  exports.default = handlers;
@@ -23,5 +23,9 @@ const handlers = {
23
23
  shouldhVePeers: false,
24
24
  };
25
25
  },
26
+ system_dryRun: async (context, [extrinsic, at]) => {
27
+ const { outcome } = await context.chain.dryRunExtrinsic(extrinsic, at);
28
+ return outcome.toHex();
29
+ },
26
30
  };
27
31
  exports.default = handlers;
package/dist/run-block.js CHANGED
@@ -30,7 +30,7 @@ const runBlock = async (argv) => {
30
30
  throw new Error(result.Error);
31
31
  }
32
32
  if (argv['html']) {
33
- const filePath = await (0, generate_html_diff_1.generateHtmlDiffPreviewFile)(block, result.Call.storageDiff, block.hash);
33
+ const filePath = await (0, generate_html_diff_1.generateHtmlDiffPreviewFile)(parent, result.Call.storageDiff, block.hash);
34
34
  console.log(`Generated preview ${filePath}`);
35
35
  if (argv['open']) {
36
36
  (0, open_html_1.openHtml)(filePath);
package/dist/setup.js CHANGED
@@ -57,6 +57,8 @@ const setup = async (argv) => {
57
57
  hash: blockHash,
58
58
  number: Number(header.number),
59
59
  },
60
+ mockSignatureHost: argv['mock-signature-host'],
61
+ allowUnresolvedImports: argv['allow-unresolved-imports'],
60
62
  });
61
63
  if (argv.timestamp)
62
64
  await (0, time_travel_1.timeTravel)(chain, argv.timestamp);
@@ -13,8 +13,15 @@ const diffPatcher = (0, jsondiffpatch_1.create)({
13
13
  array: { detectMove: false },
14
14
  textDiff: { minLength: Number.MAX_VALUE }, // skip text diff
15
15
  });
16
- const cache = {};
16
+ const _CACHE = {};
17
+ const getCache = (uid) => {
18
+ if (!_CACHE[uid]) {
19
+ _CACHE[uid] = {};
20
+ }
21
+ return _CACHE[uid];
22
+ };
17
23
  const getStorageEntry = async (block, key) => {
24
+ const cache = getCache(block.chain.uid);
18
25
  for (const [prefix, storageEntry] of Object.entries(cache)) {
19
26
  if (key.startsWith(prefix))
20
27
  return storageEntry;
@@ -87,13 +94,10 @@ const decodeKeyValue = async (block, key, value) => {
87
94
  };
88
95
  exports.decodeKeyValue = decodeKeyValue;
89
96
  const decodeStorageDiff = async (block, diff) => {
90
- const parent = await block.parentBlock;
91
- if (!parent)
92
- throw new Error('Cannot find parent block');
93
97
  const oldState = {};
94
98
  const newState = {};
95
99
  for (const [key, value] of diff) {
96
- lodash_1.default.merge(oldState, await (0, exports.decodeKeyValue)(parent, key, (await parent.get(key))));
100
+ lodash_1.default.merge(oldState, await (0, exports.decodeKeyValue)(block, key, (await block.get(key))));
97
101
  lodash_1.default.merge(newState, await (0, exports.decodeKeyValue)(block, key, value));
98
102
  }
99
103
  return [oldState, newState, diffPatcher.diff(oldState, newState)];
@@ -0,0 +1,2 @@
1
+ import { Blockchain } from '../blockchain';
2
+ export declare const connectDownward: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectDownward = void 0;
4
+ const util_1 = require("@polkadot/util");
5
+ const utils_1 = require("../utils");
6
+ const _1 = require(".");
7
+ const set_storage_1 = require("../utils/set-storage");
8
+ const connectDownward = async (relaychain, parachain) => {
9
+ const meta = await relaychain.head.meta;
10
+ const paraId = await (0, utils_1.getParaId)(parachain);
11
+ const downwardMessageQueuesKey = (0, utils_1.compactHex)(meta.query.dmp.downwardMessageQueues(paraId));
12
+ await relaychain.headState.subscribeStorage([downwardMessageQueuesKey], async (head, pairs) => {
13
+ const value = pairs[0][1];
14
+ if (!value)
15
+ return;
16
+ const meta = await relaychain.head.meta;
17
+ const downwardMessageQueuesKey = (0, utils_1.compactHex)(meta.query.dmp.downwardMessageQueues(paraId));
18
+ // clear relaychain message queue
19
+ await (0, set_storage_1.setStorage)(relaychain, [[downwardMessageQueuesKey, null]], head.hash);
20
+ const downwardMessages = meta.registry
21
+ .createType('Vec<PolkadotCorePrimitivesInboundDownwardMessage>', (0, util_1.hexToU8a)(value))
22
+ .toJSON();
23
+ _1.logger.debug({ downwardMessages }, 'downward_message');
24
+ await parachain.newBlock({ inherent: { downwardMessages } });
25
+ });
26
+ };
27
+ exports.connectDownward = connectDownward;
@@ -0,0 +1,2 @@
1
+ import { Blockchain } from '../blockchain';
2
+ export declare const connectHorizontal: (parachains: Record<number, Blockchain>) => Promise<void>;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectHorizontal = void 0;
4
+ const util_1 = require("@polkadot/util");
5
+ const utils_1 = require("../utils");
6
+ const _1 = require(".");
7
+ const set_storage_1 = require("../utils/set-storage");
8
+ const connectHorizontal = async (parachains) => {
9
+ for (const [id, chain] of Object.entries(parachains)) {
10
+ const meta = await chain.head.meta;
11
+ const hrmpOutboundMessagesKey = (0, utils_1.compactHex)(meta.query.parachainSystem.hrmpOutboundMessages());
12
+ await chain.headState.subscribeStorage([hrmpOutboundMessagesKey], async (head, pairs) => {
13
+ const value = pairs[0][1];
14
+ if (!value)
15
+ return;
16
+ const meta = await chain.head.meta;
17
+ const hrmpOutboundMessagesKey = (0, utils_1.compactHex)(meta.query.parachainSystem.hrmpOutboundMessages());
18
+ // clear sender message queue
19
+ await (0, set_storage_1.setStorage)(chain, [[hrmpOutboundMessagesKey, null]], head.hash);
20
+ const outboundHrmpMessage = meta.registry
21
+ .createType('Vec<PolkadotCorePrimitivesOutboundHrmpMessage>', (0, util_1.hexToU8a)(value))
22
+ .toJSON();
23
+ _1.logger.info({ outboundHrmpMessage }, 'outboundHrmpMessage');
24
+ for (const { recipient, data } of outboundHrmpMessage) {
25
+ const horizontalMessages = {
26
+ [Number(id)]: [{ sentAt: chain.head.number, data }],
27
+ };
28
+ const receiver = parachains[recipient];
29
+ if (receiver) {
30
+ await receiver.newBlock({ inherent: { horizontalMessages } });
31
+ }
32
+ }
33
+ });
34
+ }
35
+ };
36
+ exports.connectHorizontal = connectHorizontal;
@@ -1,3 +1,9 @@
1
1
  import { Blockchain } from '../blockchain';
2
- export declare const connectDownward: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
2
+ export declare const logger: import("pino").default.Logger<{
3
+ level: string;
4
+ transport: {
5
+ target: string;
6
+ };
7
+ } & import("pino").default.ChildLoggerOptions>;
8
+ export declare const connectVertical: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
3
9
  export declare const connectParachains: (parachains: Blockchain[]) => Promise<void>;
package/dist/xcm/index.js CHANGED
@@ -1,67 +1,25 @@
1
1
  "use strict";
2
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");
3
+ exports.connectParachains = exports.connectVertical = exports.logger = void 0;
4
+ const downward_1 = require("./downward");
5
+ const horizontal_1 = require("./horizontal");
6
+ const upward_1 = require("./upward");
6
7
  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()}'`);
8
+ const utils_1 = require("../utils");
9
+ exports.logger = logger_1.defaultLogger.child({ name: 'xcm' });
10
+ const connectVertical = async (relaychain, parachain) => {
11
+ await (0, downward_1.connectDownward)(relaychain, parachain);
12
+ await (0, upward_1.connectUpward)(parachain, relaychain);
13
+ exports.logger.info(`Connected relaychain '${await relaychain.api.getSystemChain()}' with parachain '${await parachain.api.getSystemChain()}'`);
28
14
  };
29
- exports.connectDownward = connectDownward;
15
+ exports.connectVertical = connectVertical;
30
16
  const connectParachains = async (parachains) => {
31
17
  const list = {};
32
18
  for (const chain of parachains) {
33
19
  const paraId = await (0, utils_1.getParaId)(chain);
34
20
  list[paraId.toNumber()] = chain;
35
21
  }
36
- await connectHorizontal(list);
37
- logger.info('Parachains connected');
22
+ await (0, horizontal_1.connectHorizontal)(list);
23
+ exports.logger.info(`Connected parachains [${Object.keys(list)}]`);
38
24
  };
39
25
  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
- };
@@ -0,0 +1,2 @@
1
+ import { Blockchain } from '../blockchain';
2
+ export declare const connectUpward: (parachain: Blockchain, relaychain: Blockchain) => Promise<void>;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectUpward = void 0;
4
+ const util_1 = require("@polkadot/util");
5
+ const utils_1 = require("../utils");
6
+ const _1 = require(".");
7
+ const set_storage_1 = require("../utils/set-storage");
8
+ const connectUpward = async (parachain, relaychain) => {
9
+ const meta = await parachain.head.meta;
10
+ const paraId = await (0, utils_1.getParaId)(parachain);
11
+ const upwardMessagesKey = (0, utils_1.compactHex)(meta.query.parachainSystem.upwardMessages());
12
+ await parachain.headState.subscribeStorage([upwardMessagesKey], async (head, pairs) => {
13
+ const value = pairs[0][1];
14
+ if (!value)
15
+ return;
16
+ const parachainMeta = await parachain.head.meta;
17
+ const upwardMessagesKey = (0, utils_1.compactHex)(parachainMeta.query.parachainSystem.upwardMessages());
18
+ // clear parachain message queue
19
+ await (0, set_storage_1.setStorage)(parachain, [[upwardMessagesKey, null]], head.hash);
20
+ const relaychainMeta = await relaychain.head.meta;
21
+ const upwardMessages = parachainMeta.registry.createType('Vec<Bytes>', (0, util_1.hexToU8a)(value));
22
+ const queueSize = parachainMeta.registry.createType('(u32, u32)', [
23
+ upwardMessages.length,
24
+ upwardMessages.map((x) => x.byteLength).reduce((s, i) => s + i, 0),
25
+ ]);
26
+ const needsDispatch = parachainMeta.registry.createType('Vec<u32>', [paraId]);
27
+ _1.logger.debug({ [paraId.toNumber()]: upwardMessages.toJSON(), queueSize: queueSize.toJSON() }, 'upward_message');
28
+ // TODO: make sure we append instead of replace
29
+ relaychain.head.pushStorageLayer().set((0, utils_1.compactHex)(relaychainMeta.query.ump.needsDispatch()), needsDispatch.toHex());
30
+ relaychain.head
31
+ .pushStorageLayer()
32
+ .set((0, utils_1.compactHex)(relaychainMeta.query.ump.relayDispatchQueues(paraId)), upwardMessages.toHex());
33
+ relaychain.head
34
+ .pushStorageLayer()
35
+ .set((0, utils_1.compactHex)(relaychainMeta.query.ump.relayDispatchQueueSize(paraId)), queueSize.toHex());
36
+ await relaychain.newBlock();
37
+ });
38
+ };
39
+ exports.connectUpward = connectUpward;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Bryan Chen <xlchen1291@gmail.com>",