@acala-network/chopsticks 0.2.3 → 0.3.0

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 (57) hide show
  1. package/README.md +6 -0
  2. package/dist/api.d.ts +3 -2
  3. package/dist/api.js +15 -20
  4. package/dist/blockchain/block-builder.d.ts +4 -0
  5. package/dist/blockchain/block-builder.js +71 -0
  6. package/dist/blockchain/block.d.ts +5 -3
  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 +7 -8
  11. package/dist/blockchain/index.js +26 -26
  12. package/dist/blockchain/inherent/index.d.ts +17 -0
  13. package/dist/blockchain/inherent/index.js +32 -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/validation-data.d.ts +25 -0
  17. package/dist/blockchain/{inherents.js → inherent/parachain/validation-data.js} +77 -46
  18. package/dist/blockchain/txpool.d.ts +17 -2
  19. package/dist/blockchain/txpool.js +46 -81
  20. package/dist/decode-key.d.ts +2 -0
  21. package/dist/decode-key.js +24 -0
  22. package/dist/executor.d.ts +17 -3
  23. package/dist/executor.js +43 -3
  24. package/dist/executor.test.js +16 -9
  25. package/dist/genesis-provider.d.ts +5 -0
  26. package/dist/genesis-provider.js +15 -3
  27. package/dist/index.d.ts +1 -18
  28. package/dist/index.js +43 -147
  29. package/dist/rpc/dev.js +11 -1
  30. package/dist/rpc/shared.d.ts +0 -4
  31. package/dist/rpc/substrate/author.d.ts +1 -1
  32. package/dist/rpc/substrate/author.js +7 -2
  33. package/dist/rpc/substrate/chain.js +2 -2
  34. package/dist/rpc/substrate/state.js +1 -1
  35. package/dist/rpc/substrate/system.js +3 -3
  36. package/dist/run-block.d.ts +2 -0
  37. package/dist/run-block.js +36 -0
  38. package/dist/schema/index.js +1 -1
  39. package/dist/server.d.ts +3 -3
  40. package/dist/server.js +26 -11
  41. package/dist/setup-with-server.d.ts +8 -0
  42. package/dist/setup-with-server.js +23 -0
  43. package/dist/setup.d.ts +10 -0
  44. package/dist/setup.js +62 -0
  45. package/dist/utils/index.d.ts +2 -0
  46. package/dist/utils/index.js +9 -1
  47. package/dist/utils/proof.d.ts +10 -2
  48. package/dist/utils/proof.js +12 -8
  49. package/dist/utils/set-storage.d.ts +2 -1
  50. package/dist/utils/time-travel.d.ts +5 -0
  51. package/dist/utils/time-travel.js +64 -0
  52. package/dist/xcm/index.d.ts +3 -0
  53. package/dist/xcm/index.js +67 -0
  54. package/package.json +5 -5
  55. package/dist/bindings.d.ts +0 -2
  56. package/dist/bindings.js +0 -31
  57. package/dist/blockchain/inherents.d.ts +0 -24
@@ -1,24 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SetValidationData = exports.InherentProviders = exports.SetTimestamp = void 0;
3
+ exports.SetValidationData = void 0;
4
4
  const types_1 = require("@polkadot/types");
5
- const utils_1 = require("../utils");
6
- const executor_1 = require("../executor");
7
5
  const util_1 = require("@polkadot/util");
8
- const proof_1 = require("../utils/proof");
9
- class SetTimestamp {
10
- #getTimestamp;
11
- constructor(getTimestamp = Date.now) {
12
- this.#getTimestamp = getTimestamp;
13
- }
14
- async createInherents(meta, timestamp, _parent) {
15
- return [new types_1.GenericExtrinsic(meta.registry, meta.tx.timestamp.set(timestamp)).toHex()];
16
- }
17
- getTimestamp(blockNumber) {
18
- return this.#getTimestamp(blockNumber);
19
- }
20
- }
21
- exports.SetTimestamp = SetTimestamp;
6
+ const util_crypto_1 = require("@polkadot/util-crypto");
7
+ const utils_1 = require("../../../utils");
8
+ const executor_1 = require("../../../executor");
9
+ const proof_1 = require("../../../utils/proof");
22
10
  const MOCK_VALIDATION_DATA = {
23
11
  validationData: {
24
12
  relayParentNumber: 1000,
@@ -43,35 +31,15 @@ const MOCK_VALIDATION_DATA = {
43
31
  ],
44
32
  },
45
33
  };
46
- class InherentProviders {
47
- #base;
48
- #providers;
49
- constructor(base, providers) {
50
- this.#base = base;
51
- this.#providers = providers;
52
- }
53
- async createInherents(meta, timestamp, parent) {
54
- const base = await this.#base.createInherents(meta, timestamp, parent);
55
- const extra = await Promise.all(this.#providers.map((provider) => provider.createInherents(meta, timestamp, parent)));
56
- return [...base, ...extra.flat()];
57
- }
58
- getTimestamp(blockNumber) {
59
- return this.#base.getTimestamp(blockNumber);
60
- }
61
- }
62
- exports.InherentProviders = InherentProviders;
63
34
  class SetValidationData {
64
- async createInherents(meta, _timestamp, parent) {
35
+ async createInherents(parent, params) {
36
+ const meta = await parent.meta;
65
37
  if (!meta.tx.parachainSystem?.setValidationData) {
66
38
  return [];
67
39
  }
68
- const parentBlock = await parent.parentBlock;
69
- if (!parentBlock) {
70
- throw new Error('Parent block not found');
71
- }
72
- const extrinsics = await parentBlock.extrinsics;
40
+ const extrinsics = await parent.extrinsics;
73
41
  let newData;
74
- if (parentBlock.number === 0) {
42
+ if (parent.number === 0) {
75
43
  // chain started with genesis, mock 1st validationData
76
44
  newData = MOCK_VALIDATION_DATA;
77
45
  }
@@ -87,17 +55,80 @@ class SetValidationData {
87
55
  .createType('GenericExtrinsic', validationDataExtrinsic)
88
56
  .args[0].toJSON();
89
57
  const newEntries = [];
90
- const upgrade = await parentBlock.get((0, utils_1.compactHex)(meta.query.parachainSystem.pendingValidationCode()));
91
- if (upgrade) {
92
- const paraIdStorage = await parentBlock.get((0, utils_1.compactHex)(meta.query.parachainInfo.parachainId()));
93
- const paraId = meta.registry.createType('u32', (0, util_1.hexToU8a)(paraIdStorage));
94
- const upgradeKey = (0, proof_1.upgradeGoAheadSignal)(paraId);
58
+ const downwardMessages = [];
59
+ const horizontalMessages = {};
60
+ const paraId = await (0, utils_1.getParaId)(parent.chain);
61
+ const dmqMqcHeadKey = (0, proof_1.dmqMqcHead)(paraId);
62
+ const hrmpIngressChannelIndexKey = (0, proof_1.hrmpIngressChannelIndex)(paraId);
63
+ const decoded = await (0, executor_1.decodeProof)(extrinsic.validationData.relayParentStorageRoot, [dmqMqcHeadKey, hrmpIngressChannelIndexKey], extrinsic.relayChainState.trieNodes);
64
+ // inject downward messages
65
+ if (params?.downwardMessages) {
66
+ let dmqMqcHeadHash = decoded[dmqMqcHeadKey];
67
+ if (!dmqMqcHeadHash)
68
+ throw new Error('Canoot find dmqMqcHead from validation data');
69
+ for (const { msg, sentAt } of params.downwardMessages) {
70
+ // calculate new hash
71
+ dmqMqcHeadHash = (0, util_crypto_1.blake2AsHex)((0, util_1.u8aConcat)(meta.registry.createType('Hash', dmqMqcHeadHash).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), (0, util_crypto_1.blake2AsU8a)(meta.registry.createType('Bytes', msg).toU8a(), 256)), 256);
72
+ downwardMessages.push({
73
+ msg,
74
+ sent_at: sentAt,
75
+ });
76
+ }
77
+ newEntries.push([dmqMqcHeadKey, dmqMqcHeadHash]);
78
+ }
79
+ const hrmpIngressChannels = meta.registry
80
+ .createType('Vec<ParaId>', decoded[hrmpIngressChannelIndexKey])
81
+ .toJSON();
82
+ // inject horizontal messages
83
+ if (params?.horizontalMessages) {
84
+ for (const [id, messages] of Object.entries(params.horizontalMessages)) {
85
+ const sender = Number(id);
86
+ if (hrmpIngressChannels.includes(sender)) {
87
+ const channelId = meta.registry.createType('HrmpChannelId', {
88
+ sender,
89
+ receiver: paraId.toNumber(),
90
+ });
91
+ const hrmpChannelKey = (0, proof_1.hrmpChannels)(channelId);
92
+ const decoded = await (0, executor_1.decodeProof)(extrinsic.validationData.relayParentStorageRoot, [hrmpChannelKey], extrinsic.relayChainState.trieNodes);
93
+ const abridgedHrmpRaw = decoded[hrmpChannelKey];
94
+ if (!abridgedHrmpRaw)
95
+ throw new Error('Canoot find hrmp channels from validation data');
96
+ const abridgedHrmp = meta.registry
97
+ .createType('AbridgedHrmpChannel', (0, util_1.hexToU8a)(abridgedHrmpRaw))
98
+ .toJSON();
99
+ const paraMessages = [];
100
+ for (const { data, sentAt } of messages) {
101
+ // calculate new hash
102
+ const bytes = meta.registry.createType('Bytes', data);
103
+ abridgedHrmp.mqcHead = (0, util_crypto_1.blake2AsHex)((0, util_1.u8aConcat)(meta.registry.createType('Hash', abridgedHrmp.mqcHead).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), (0, util_crypto_1.blake2AsU8a)(bytes.toU8a(), 256)), 256);
104
+ abridgedHrmp.msgCount = abridgedHrmp.msgCount + 1;
105
+ abridgedHrmp.totalSize = abridgedHrmp.totalSize + bytes.length;
106
+ paraMessages.push({
107
+ data,
108
+ sent_at: sentAt,
109
+ });
110
+ }
111
+ horizontalMessages[sender] = paraMessages;
112
+ newEntries.push([hrmpChannelKey, meta.registry.createType('AbridgedHrmpChannel', abridgedHrmp).toHex()]);
113
+ }
114
+ }
115
+ }
116
+ const upgradeKey = (0, proof_1.upgradeGoAheadSignal)(paraId);
117
+ const pendingUpgrade = await parent.get((0, utils_1.compactHex)(meta.query.parachainSystem.pendingValidationCode()));
118
+ if (pendingUpgrade) {
119
+ // send goAhead signal
95
120
  const goAhead = meta.registry.createType('UpgradeGoAhead', 'GoAhead');
96
121
  newEntries.push([upgradeKey, goAhead.toHex()]);
97
122
  }
123
+ else {
124
+ // make sure previous goAhead is removed
125
+ newEntries.push([upgradeKey, null]);
126
+ }
98
127
  const { trieRootHash, nodes } = await (0, executor_1.createProof)(extrinsic.validationData.relayParentStorageRoot, extrinsic.relayChainState.trieNodes, newEntries);
99
128
  newData = {
100
129
  ...extrinsic,
130
+ downwardMessages,
131
+ horizontalMessages,
101
132
  validationData: {
102
133
  ...extrinsic.validationData,
103
134
  relayParentStorageRoot: trieRootHash,
@@ -1,14 +1,29 @@
1
1
  import { HexString } from '@polkadot/util/types';
2
2
  import { Blockchain } from '.';
3
- import { InherentProvider } from './inherents';
3
+ import { InherentProvider } from './inherent';
4
4
  export declare enum BuildBlockMode {
5
5
  Batch = 0,
6
6
  Instant = 1,
7
7
  Manual = 2
8
8
  }
9
+ export interface DownwardMessage {
10
+ sentAt: number;
11
+ msg: HexString;
12
+ }
13
+ export interface HorizontalMessage {
14
+ sentAt: number;
15
+ data: HexString;
16
+ }
17
+ export interface BuildBlockParams {
18
+ inherent?: {
19
+ downwardMessages?: DownwardMessage[];
20
+ horizontalMessages?: Record<number, HorizontalMessage[]>;
21
+ };
22
+ }
9
23
  export declare class TxPool {
10
24
  #private;
11
25
  constructor(chain: Blockchain, inherentProvider: InherentProvider, mode?: BuildBlockMode);
26
+ get pendingExtrinsics(): HexString[];
12
27
  submitExtrinsic(extrinsic: HexString): void;
13
- buildBlock(): Promise<void>;
28
+ buildBlock(params?: BuildBlockParams): Promise<void>;
14
29
  }
@@ -6,11 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TxPool = exports.BuildBlockMode = void 0;
7
7
  const util_1 = require("@polkadot/util");
8
8
  const lodash_1 = __importDefault(require("lodash"));
9
- const block_1 = require("./block");
10
- const shared_1 = require("../rpc/shared");
11
- const utils_1 = require("../utils");
12
- const logger_1 = require("../logger");
13
- const logger = logger_1.defaultLogger.child({ name: 'txpool' });
9
+ const block_builder_1 = require("./block-builder");
10
+ const time_travel_1 = require("../utils/time-travel");
14
11
  var BuildBlockMode;
15
12
  (function (BuildBlockMode) {
16
13
  BuildBlockMode[BuildBlockMode["Batch"] = 0] = "Batch";
@@ -21,8 +18,35 @@ const getConsensus = (header) => {
21
18
  if (header.digest.logs.length === 0)
22
19
  return;
23
20
  const preRuntime = header.digest.logs[0].asPreRuntime;
24
- const [consensusEngine] = preRuntime;
25
- return { consensusEngine, rest: header.digest.logs.slice(1) };
21
+ const [consensusEngine, slot] = preRuntime;
22
+ return { consensusEngine, slot, rest: header.digest.logs.slice(1) };
23
+ };
24
+ const getNewSlot = (digest, slotNumber) => {
25
+ if (digest.isPrimary) {
26
+ return {
27
+ primary: {
28
+ ...digest.asPrimary.toJSON(),
29
+ slotNumber,
30
+ },
31
+ };
32
+ }
33
+ if (digest.isSecondaryPlain) {
34
+ return {
35
+ secondaryPlain: {
36
+ ...digest.asSecondaryPlain.toJSON(),
37
+ slotNumber,
38
+ },
39
+ };
40
+ }
41
+ if (digest.isSecondaryVRF) {
42
+ return {
43
+ secondaryVRF: {
44
+ ...digest.asSecondaryVRF.toJSON(),
45
+ slotNumber,
46
+ },
47
+ };
48
+ }
49
+ return digest.toJSON();
26
50
  };
27
51
  class TxPool {
28
52
  #chain;
@@ -35,6 +59,9 @@ class TxPool {
35
59
  this.#mode = mode;
36
60
  this.#inherentProvider = inherentProvider;
37
61
  }
62
+ get pendingExtrinsics() {
63
+ return this.#pool;
64
+ }
38
65
  submitExtrinsic(extrinsic) {
39
66
  this.#pool.push(extrinsic);
40
67
  switch (this.#mode) {
@@ -50,29 +77,29 @@ class TxPool {
50
77
  }
51
78
  }
52
79
  #batchBuildBlock = lodash_1.default.debounce(this.buildBlock, 100, { maxWait: 1000 });
53
- async buildBlock() {
80
+ async buildBlock(params) {
54
81
  const last = this.#lastBuildBlockPromise;
55
- this.#lastBuildBlockPromise = this.#buildBlock(last);
82
+ this.#lastBuildBlockPromise = this.#buildBlock(last, params);
56
83
  await this.#lastBuildBlockPromise;
57
84
  }
58
- async #buildBlock(wait) {
85
+ async #buildBlock(wait, params) {
59
86
  await this.#chain.api.isReady;
60
87
  await wait.catch(() => { }); // ignore error
61
88
  const head = this.#chain.head;
62
89
  const extrinsics = this.#pool.splice(0);
63
90
  const meta = await head.meta;
64
91
  const parentHeader = await head.header;
65
- const time = this.#inherentProvider.getTimestamp(head.number + 1);
66
92
  let newLogs = parentHeader.digest.logs;
67
- const expectedSlot = Math.floor(time / (meta.consts.timestamp.minimumPeriod.toNumber() * 2));
68
93
  const consensus = getConsensus(parentHeader);
69
94
  if (consensus?.consensusEngine.isAura) {
70
- const newSlot = (0, util_1.compactAddLength)((0, util_1.bnToU8a)(expectedSlot, { isLe: true, bitLength: 64 }));
95
+ const slot = await (0, time_travel_1.getCurrentSlot)(this.#chain);
96
+ const newSlot = (0, util_1.compactAddLength)(meta.registry.createType('Slot', slot + 1).toU8a());
71
97
  newLogs = [{ PreRuntime: [consensus.consensusEngine, newSlot] }, ...consensus.rest];
72
98
  }
73
99
  else if (consensus?.consensusEngine.isBabe) {
74
- // trying to make a SecondaryPlainPreDigest
75
- const newSlot = (0, util_1.compactAddLength)((0, util_1.u8aConcat)('0x0200000000', (0, util_1.bnToU8a)(expectedSlot, { isLe: true, bitLength: 64 })));
100
+ const slot = await (0, time_travel_1.getCurrentSlot)(this.#chain);
101
+ const digest = meta.registry.createType('RawBabePreDigest', consensus.slot);
102
+ const newSlot = (0, util_1.compactAddLength)(meta.registry.createType('RawBabePreDigest', getNewSlot(digest, slot + 1)).toU8a());
76
103
  newLogs = [{ PreRuntime: [consensus.consensusEngine, newSlot] }, ...consensus.rest];
77
104
  }
78
105
  const registry = await head.registry;
@@ -85,72 +112,10 @@ class TxPool {
85
112
  logs: newLogs,
86
113
  },
87
114
  });
88
- const newBlock = this.#chain.newTempBlock(head, header);
89
- logger.info({
90
- hash: head.hash,
91
- number: head.number,
92
- extrinsicsCount: extrinsics.length,
93
- tempHash: newBlock.hash,
94
- timeValue: time,
95
- expectedSlot,
96
- }, 'Building block');
97
- const resp = await newBlock.call('Core_initialize_block', header.toHex());
98
- logger.trace((0, logger_1.truncateStorageDiff)(resp.storageDiff), 'Initialize block');
99
- newBlock.pushStorageLayer().setAll(resp.storageDiff);
100
- if (meta.query.babe?.currentSlot) {
101
- // TODO: figure out how to generate a valid babe slot digest instead of just modify the data
102
- // but hey, we can get it working without a valid digest
103
- const key = (0, utils_1.compactHex)(meta.query.babe.currentSlot());
104
- newBlock.pushStorageLayer().set(key, (0, util_1.bnToHex)(expectedSlot, { isLe: true, bitLength: 64 }));
105
- }
106
- const inherents = await this.#inherentProvider.createInherents(meta, time, newBlock);
107
- for (const extrinsic of inherents) {
108
- try {
109
- const resp = await newBlock.call('BlockBuilder_apply_extrinsic', extrinsic);
110
- newBlock.pushStorageLayer().setAll(resp.storageDiff);
111
- logger.trace((0, logger_1.truncateStorageDiff)(resp.storageDiff), 'Applied inherent');
112
- }
113
- catch (e) {
114
- logger.warn('Failed to apply inherents %o %s', e, e);
115
- throw new shared_1.ResponseError(1, 'Failed to apply inherents');
116
- }
117
- }
118
- for (const extrinsic of extrinsics) {
119
- try {
120
- const resp = await newBlock.call('BlockBuilder_apply_extrinsic', extrinsic);
121
- newBlock.pushStorageLayer().setAll(resp.storageDiff);
122
- logger.trace((0, logger_1.truncateStorageDiff)(resp.storageDiff), 'Applied extrinsic');
123
- }
124
- catch (e) {
125
- logger.info('Failed to apply extrinsic %o %s', e, e);
126
- this.#pool.push(extrinsic);
127
- }
128
- }
129
- if (meta.query.paraInherent?.included) {
130
- // TODO: remvoe this once paraInherent.enter is implemented
131
- // we are relaychain, however as we have not yet implemented the paraInherent.enter
132
- // so need to do some trick to make the on_finalize check happy
133
- const paraInherentIncludedKey = (0, utils_1.compactHex)(meta.query.paraInherent.included());
134
- newBlock.pushStorageLayer().set(paraInherentIncludedKey, '0x01');
135
- }
136
- const resp2 = await newBlock.call('BlockBuilder_finalize_block', '0x');
137
- newBlock.pushStorageLayer().setAll(resp2.storageDiff);
138
- logger.trace((0, logger_1.truncateStorageDiff)(resp2.storageDiff), 'Finalize block');
139
- const blockData = registry.createType('Block', {
140
- header,
141
- extrinsics,
142
- });
143
- const finalBlock = new block_1.Block(this.#chain, newBlock.number, blockData.hash.toHex(), head, {
144
- header,
145
- extrinsics: [...inherents, ...extrinsics],
146
- storage: head.storage,
147
- });
148
- const diff = await newBlock.storageDiff();
149
- logger.trace(Object.entries(diff).map(([key, value]) => [key, (0, logger_1.truncate)(value)]), 'Final block');
150
- finalBlock.pushStorageLayer().setAll(diff);
151
- this.#chain.unregisterBlock(newBlock);
152
- this.#chain.setHead(finalBlock);
153
- logger.info({ hash: finalBlock.hash, number: finalBlock.number, prevHash: newBlock.hash }, 'Block built');
115
+ const inherents = await this.#inherentProvider.createInherents(head, params?.inherent);
116
+ const [newBlock, pendingExtrinsics] = await (0, block_builder_1.buildBlock)(head, header, inherents, extrinsics);
117
+ this.#pool.push(...pendingExtrinsics);
118
+ await this.#chain.setHead(newBlock);
154
119
  }
155
120
  }
156
121
  exports.TxPool = TxPool;
@@ -0,0 +1,2 @@
1
+ import '@polkadot/types-codec';
2
+ export declare const decodeKey: (argv: any) => Promise<void>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decodeKey = void 0;
4
+ require("@polkadot/types-codec");
5
+ const util_1 = require("@polkadot/util");
6
+ const setup_1 = require("./setup");
7
+ const decodeKey = async (argv) => {
8
+ const context = await (0, setup_1.setup)(argv);
9
+ const key = argv.key;
10
+ const meta = await context.chain.head.meta;
11
+ outer: for (const module of Object.values(meta.query)) {
12
+ for (const storage of Object.values(module)) {
13
+ const keyPrefix = (0, util_1.u8aToHex)(storage.keyPrefix());
14
+ if (key.startsWith(keyPrefix)) {
15
+ const decodedKey = meta.registry.createType('StorageKey', key);
16
+ decodedKey.setMeta(storage.meta);
17
+ console.log(`${storage.section}.${storage.method}`, decodedKey.args.map((x) => JSON.stringify(x.toHuman())).join(', '));
18
+ break outer;
19
+ }
20
+ }
21
+ }
22
+ setTimeout(() => process.exit(0), 50);
23
+ };
24
+ exports.decodeKey = decodeKey;
@@ -1,4 +1,11 @@
1
1
  import { HexString } from '@polkadot/util/types';
2
+ import { Block } from './blockchain/block';
3
+ import { Registry } from '@polkadot/types-codec/types';
4
+ interface JsCallback {
5
+ getStorage: (key: HexString) => Promise<string | undefined>;
6
+ getPrefixKeys: (key: HexString) => Promise<string[]>;
7
+ getNextKey: (key: HexString) => Promise<string | undefined>;
8
+ }
2
9
  export type RuntimeVersion = {
3
10
  specName: string;
4
11
  implName: string;
@@ -12,15 +19,22 @@ export type RuntimeVersion = {
12
19
  export declare const getRuntimeVersion: (code: HexString) => Promise<RuntimeVersion>;
13
20
  export declare const calculateStateRoot: (entries: [HexString, HexString][]) => Promise<HexString>;
14
21
  export declare const decodeProof: (trieRootHash: HexString, keys: HexString[], nodes: HexString[]) => Promise<Record<`0x${string}`, `0x${string}` | null>>;
15
- export declare const createProof: (trieRootHash: HexString, nodes: HexString[], entries: [HexString, HexString][]) => Promise<{
22
+ export declare const createProof: (trieRootHash: HexString, nodes: HexString[], entries: [HexString, HexString | null][]) => Promise<{
16
23
  trieRootHash: `0x${string}`;
17
24
  nodes: `0x${string}`[];
18
25
  }>;
19
26
  export declare const runTask: (task: {
20
- blockHash: HexString;
21
27
  wasm: HexString;
22
28
  calls: [string, HexString][];
23
29
  storage: [HexString, HexString | null][];
24
30
  mockSignatureHost: boolean;
25
31
  allowUnresolvedImports: boolean;
26
- }) => Promise<any>;
32
+ }, callback?: JsCallback) => Promise<any>;
33
+ export declare const taskHandler: (block: Block) => JsCallback;
34
+ export declare const emptyTaskHandler: {
35
+ getStorage: (_key: HexString) => Promise<never>;
36
+ getPrefixKeys: (_key: HexString) => Promise<never>;
37
+ getNextKey: (_key: HexString) => Promise<never>;
38
+ };
39
+ export declare const getAuraSlotDuration: ((wasm: HexString, registry: Registry) => Promise<number>) & import("lodash").MemoizedFunction;
40
+ export {};
package/dist/executor.js CHANGED
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runTask = exports.createProof = exports.decodeProof = exports.calculateStateRoot = exports.getRuntimeVersion = void 0;
3
+ exports.getAuraSlotDuration = exports.emptyTaskHandler = exports.taskHandler = exports.runTask = exports.createProof = exports.decodeProof = exports.calculateStateRoot = exports.getRuntimeVersion = void 0;
4
4
  const ws_1 = require("ws");
5
5
  const util_1 = require("@polkadot/util");
6
6
  global.WebSocket = ws_1.WebSocket;
7
7
  const chopsticks_executor_1 = require("@acala-network/chopsticks-executor");
8
8
  const logger_1 = require("./logger");
9
+ const lodash_1 = require("lodash");
9
10
  const logger = logger_1.defaultLogger.child({ name: 'executor' });
10
11
  const getRuntimeVersion = async (code) => {
11
12
  return (0, chopsticks_executor_1.get_runtime_version)(code).then((version) => {
@@ -36,9 +37,9 @@ const createProof = async (trieRootHash, nodes, entries) => {
36
37
  return { trieRootHash: result[0], nodes: result[1] };
37
38
  };
38
39
  exports.createProof = createProof;
39
- const runTask = async (task) => {
40
+ const runTask = async (task, callback = exports.emptyTaskHandler) => {
40
41
  logger.trace({ task: { ...task, wasm: (0, logger_1.truncate)(task.wasm) } }, 'taskRun');
41
- const response = await (0, chopsticks_executor_1.run_task)(task);
42
+ const response = await (0, chopsticks_executor_1.run_task)(task, callback);
42
43
  if (response.Call) {
43
44
  logger.trace({ result: (0, logger_1.truncate)(response.Call.result), storageDiff: (0, logger_1.truncateStorageDiff)(response.Call.storageDiff) }, 'taskResponse');
44
45
  }
@@ -48,3 +49,42 @@ const runTask = async (task) => {
48
49
  return response;
49
50
  };
50
51
  exports.runTask = runTask;
52
+ const taskHandler = (block) => {
53
+ return {
54
+ getStorage: async function (key) {
55
+ return block.get(key);
56
+ },
57
+ getPrefixKeys: async function (key) {
58
+ return block.getKeysPaged({ prefix: key, pageSize: 1000, startKey: key });
59
+ },
60
+ getNextKey: async function (key) {
61
+ const keys = await block.getKeysPaged({ prefix: key, pageSize: 1, startKey: key });
62
+ return keys[0];
63
+ },
64
+ };
65
+ };
66
+ exports.taskHandler = taskHandler;
67
+ exports.emptyTaskHandler = {
68
+ getStorage: async function (_key) {
69
+ throw new Error('Method not implemented');
70
+ },
71
+ getPrefixKeys: async function (_key) {
72
+ throw new Error('Method not implemented');
73
+ },
74
+ getNextKey: async function (_key) {
75
+ throw new Error('Method not implemented');
76
+ },
77
+ };
78
+ exports.getAuraSlotDuration = (0, lodash_1.memoize)(async (wasm, registry) => {
79
+ const result = await (0, exports.runTask)({
80
+ wasm,
81
+ calls: [['AuraApi_slot_duration', '0x']],
82
+ storage: [],
83
+ mockSignatureHost: false,
84
+ allowUnresolvedImports: false,
85
+ });
86
+ if (!result.Call)
87
+ throw new Error(result.Error);
88
+ const slotDuration = registry.createType('u64', (0, util_1.hexToU8a)(result.Call.result)).toNumber();
89
+ return slotDuration;
90
+ });
@@ -9,20 +9,23 @@ const node_fs_1 = require("node:fs");
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const proof_1 = require("./utils/proof");
11
11
  const executor_1 = require("./executor");
12
+ const getCode = () => {
13
+ const code = String((0, node_fs_1.readFileSync)(node_path_1.default.join(__dirname, '../e2e/blobs/acala-runtime-2101.txt'))).trim();
14
+ (0, vitest_1.expect)(code.length).toBeGreaterThan(2);
15
+ return code;
16
+ };
12
17
  (0, vitest_1.describe)('wasm', () => {
13
18
  (0, vitest_1.it)('get runtime version from wasm runtime', async () => {
14
- const code = String((0, node_fs_1.readFileSync)(node_path_1.default.join(__dirname, 'runtime.example'))).trim();
15
- (0, vitest_1.expect)(code.length).toBeGreaterThan(2);
16
19
  const expectedRuntimeVersion = {
17
20
  specName: 'acala',
18
21
  implName: 'acala',
19
22
  authoringVersion: 1,
20
- specVersion: 2000,
23
+ specVersion: 2101,
21
24
  implVersion: 0,
22
25
  apis: [
23
- ['0xdf6acb689907609b', 3],
26
+ ['0xdf6acb689907609b', 4],
24
27
  ['0x37e397fc7c91f5e4', 1],
25
- ['0x40fe3ad401f8959a', 5],
28
+ ['0x40fe3ad401f8959a', 6],
26
29
  ['0xd2bc9897eed08f15', 3],
27
30
  ['0xf78b278be53f454c', 2],
28
31
  ['0xdd718d5cc53262d4', 1],
@@ -30,14 +33,14 @@ const executor_1 = require("./executor");
30
33
  ['0xbc9d89904f5b923f', 1],
31
34
  ['0x37c8bb1350a9a2a8', 1],
32
35
  ['0x6ef953004ba30e59', 1],
33
- ['0xf485c9145d3f0aad', 1],
34
- ['0xe3df3f2aa8a5cc57', 1],
35
- ['0xea93e3f16f3d6962', 1],
36
+ ['0x955e168e0cfb3409', 1],
37
+ ['0xe3df3f2aa8a5cc57', 2],
38
+ ['0xea93e3f16f3d6962', 2],
36
39
  ],
37
40
  transactionVersion: 1,
38
41
  stateVersion: 0,
39
42
  };
40
- (0, vitest_1.expect)(await (0, executor_1.getRuntimeVersion)(code)).toMatchObject(expectedRuntimeVersion);
43
+ (0, vitest_1.expect)(await (0, executor_1.getRuntimeVersion)(getCode())).toMatchObject(expectedRuntimeVersion);
41
44
  });
42
45
  (0, vitest_1.it)('calculate state root', async () => {
43
46
  const a = await (0, executor_1.calculateStateRoot)([['0x5301bf5ff0298f5c7b93a446709f8e885f772afdd0d8ba3d4d559a06f0742f12', '0x01']]);
@@ -128,4 +131,8 @@ const executor_1 = require("./executor");
128
131
  (0, vitest_1.expect)(decoded).toMatchSnapshot();
129
132
  (0, vitest_1.expect)(decoded[upgradeKey]).toBe('0x01');
130
133
  });
134
+ (0, vitest_1.it)('get aura slot duration', async () => {
135
+ const slotDuration = await (0, executor_1.getAuraSlotDuration)(getCode(), new types_1.TypeRegistry());
136
+ (0, vitest_1.expect)(slotDuration).eq(12000);
137
+ });
131
138
  });
@@ -36,6 +36,11 @@ export declare class GenesisProvider implements ProviderInterface {
36
36
  extrinsics: never[];
37
37
  };
38
38
  }>;
39
+ get _jsCallback(): {
40
+ getStorage: (key: HexString) => Promise<string>;
41
+ getNextKey: (_key: HexString) => Promise<string>;
42
+ getPrefixKeys: (_key: HexString) => Promise<never[]>;
43
+ };
39
44
  send: (method: string, params: unknown[], _isCacheable?: boolean) => Promise<any>;
40
45
  subscribe: (_type: string, _method: string, _params: unknown[], _cb: ProviderInterfaceCallback) => Promise<number | string>;
41
46
  unsubscribe: (_type: string, _method: string, _id: number | string) => Promise<boolean>;
@@ -30,7 +30,6 @@ class GenesisProvider {
30
30
  });
31
31
  this.#eventemitter.once('error', reject);
32
32
  });
33
- this.connect();
34
33
  }
35
34
  static fromUrl = async (url) => {
36
35
  let isUrl = false;
@@ -103,6 +102,20 @@ class GenesisProvider {
103
102
  },
104
103
  };
105
104
  };
105
+ get _jsCallback() {
106
+ const storage = this.#genesis.genesis.raw.top;
107
+ return {
108
+ getStorage: async function (key) {
109
+ return storage[key];
110
+ },
111
+ getNextKey: async function (_key) {
112
+ return '0x';
113
+ },
114
+ getPrefixKeys: async function (_key) {
115
+ return [];
116
+ },
117
+ };
118
+ }
106
119
  send = async (method, params, _isCacheable) => {
107
120
  await this.isReady;
108
121
  switch (method) {
@@ -115,13 +128,12 @@ class GenesisProvider {
115
128
  case 'state_getMetadata': {
116
129
  const code = this.#genesis.genesis.raw.top[(0, util_1.stringToHex)(':code')];
117
130
  return (0, executor_1.runTask)({
118
- blockHash: this.blockHash,
119
131
  wasm: code,
120
132
  calls: [['Metadata_metadata', '0x']],
121
133
  storage: [],
122
134
  mockSignatureHost: false,
123
135
  allowUnresolvedImports: true,
124
- });
136
+ }, this._jsCallback);
125
137
  }
126
138
  case 'chain_getHeader':
127
139
  return this.getHeader();
package/dist/index.d.ts CHANGED
@@ -1,18 +1 @@
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
- }>;
11
- export declare const setupWithServer: (argv: Config) => Promise<{
12
- close: () => Promise<void>;
13
- chain: Blockchain;
14
- api: Api;
15
- ws: ProviderInterface;
16
- }>;
17
- export declare const runBlock: (argv: Config) => Promise<void>;
18
- export declare const decodeKey: (argv: any) => Promise<void>;
1
+ export {};