@acala-network/chopsticks-core 0.9.0 → 0.9.1-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/dist/cjs/api.js CHANGED
@@ -124,6 +124,18 @@ class Api {
124
124
  return __classPrivateFieldGet(this, _Api_provider, "f").send('state_getKeysPaged', params, !!hash);
125
125
  }
126
126
  }
127
+ async subscribeRemoteNewHeads(cb) {
128
+ if (!__classPrivateFieldGet(this, _Api_provider, "f").hasSubscriptions) {
129
+ throw new Error('subscribeRemoteNewHeads only works with subscriptions');
130
+ }
131
+ return __classPrivateFieldGet(this, _Api_provider, "f").subscribe('chain_newHead', 'chain_subscribeNewHeads', [], cb);
132
+ }
133
+ async subscribeRemoteFinalizedHeads(cb) {
134
+ if (!__classPrivateFieldGet(this, _Api_provider, "f").hasSubscriptions) {
135
+ throw new Error('subscribeRemoteFinalizedHeads only works with subscriptions');
136
+ }
137
+ return __classPrivateFieldGet(this, _Api_provider, "f").subscribe('chain_finalizedHead', 'chain_subscribeFinalizedHeads', [], cb);
138
+ }
127
139
  }
128
140
  exports.Api = Api;
129
141
  _Api_provider = new WeakMap(), _Api_ready = new WeakMap(), _Api_chain = new WeakMap(), _Api_chainProperties = new WeakMap();
@@ -16,7 +16,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
16
16
  var _TxPool_instances, _TxPool_chain, _TxPool_pool, _TxPool_ump, _TxPool_dmp, _TxPool_hrmp, _TxPool_mode, _TxPool_inherentProvider, _TxPool_pendingBlocks, _TxPool_isBuilding, _TxPool_getSigner, _TxPool_maybeBuildBlock, _TxPool_batchBuildBlock, _TxPool_buildBlockIfNeeded, _TxPool_buildBlock;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.TxPool = exports.BuildBlockMode = exports.APPLY_EXTRINSIC_ERROR = void 0;
19
- const eventemitter3_1 = require("eventemitter3");
19
+ const eventemitter3_1 = __importDefault(require("eventemitter3"));
20
20
  const lodash_1 = __importDefault(require("lodash"));
21
21
  const utils_1 = require("../utils");
22
22
  const block_builder_1 = require("./block-builder");
@@ -43,7 +43,7 @@ class TxPool {
43
43
  _TxPool_mode.set(this, void 0);
44
44
  _TxPool_inherentProvider.set(this, void 0);
45
45
  _TxPool_pendingBlocks.set(this, []);
46
- this.event = new eventemitter3_1.EventEmitter();
46
+ this.event = new eventemitter3_1.default();
47
47
  _TxPool_isBuilding.set(this, false);
48
48
  _TxPool_batchBuildBlock.set(this, lodash_1.default.debounce(this.buildBlock, 100, { maxWait: 1000 }));
49
49
  __classPrivateFieldSet(this, _TxPool_chain, chain, "f");
@@ -10,10 +10,13 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
13
16
  var _a, _ChopsticksProvider_isConnected, _ChopsticksProvider_eventemitter, _ChopsticksProvider_isReadyPromise, _ChopsticksProvider_subscriptions;
14
17
  Object.defineProperty(exports, "__esModule", { value: true });
15
18
  exports.ChopsticksProvider = void 0;
16
- const eventemitter3_1 = require("eventemitter3");
19
+ const eventemitter3_1 = __importDefault(require("eventemitter3"));
17
20
  const rpc_1 = require("./rpc");
18
21
  const logger_1 = require("./logger");
19
22
  const setup_1 = require("./setup");
@@ -113,7 +116,7 @@ class ChopsticksProvider {
113
116
  throw e;
114
117
  }
115
118
  };
116
- __classPrivateFieldSet(this, _ChopsticksProvider_eventemitter, new eventemitter3_1.EventEmitter(), "f");
119
+ __classPrivateFieldSet(this, _ChopsticksProvider_eventemitter, new eventemitter3_1.default(), "f");
117
120
  __classPrivateFieldSet(this, _ChopsticksProvider_isReadyPromise, new Promise((resolve, reject) => {
118
121
  __classPrivateFieldGet(this, _ChopsticksProvider_eventemitter, "f").once('connected', resolve);
119
122
  __classPrivateFieldGet(this, _ChopsticksProvider_eventemitter, "f").once('error', reject);
@@ -10,10 +10,13 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
13
16
  var _GenesisProvider_isConnected, _GenesisProvider_eventemitter, _GenesisProvider_isReadyPromise, _GenesisProvider_genesis, _GenesisProvider_stateRoot;
14
17
  Object.defineProperty(exports, "__esModule", { value: true });
15
18
  exports.GenesisProvider = void 0;
16
- const eventemitter3_1 = require("eventemitter3");
19
+ const eventemitter3_1 = __importDefault(require("eventemitter3"));
17
20
  const schema_1 = require("./schema");
18
21
  const wasm_executor_1 = require("./wasm-executor");
19
22
  /**
@@ -104,7 +107,7 @@ class GenesisProvider {
104
107
  accu.push(item);
105
108
  return accu;
106
109
  }, []), 1), "f");
107
- __classPrivateFieldSet(this, _GenesisProvider_eventemitter, new eventemitter3_1.EventEmitter(), "f");
110
+ __classPrivateFieldSet(this, _GenesisProvider_eventemitter, new eventemitter3_1.default(), "f");
108
111
  __classPrivateFieldSet(this, _GenesisProvider_isReadyPromise, new Promise((resolve, reject) => {
109
112
  __classPrivateFieldGet(this, _GenesisProvider_eventemitter, "f").once('connected', () => {
110
113
  resolve();
@@ -3,11 +3,11 @@ 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.decodeBlockStorageDiff = exports.decodeKeyValue = exports.decodeKey = void 0;
6
+ exports.decodeBlockStorageDiff = exports.toStorageObject = exports.decodeKeyValue = exports.decodeKey = void 0;
7
7
  require("@polkadot/types-codec");
8
- const util_crypto_1 = require("@polkadot/util-crypto");
9
8
  const util_1 = require("@polkadot/util");
10
9
  const lodash_1 = __importDefault(require("lodash"));
10
+ const well_known_keys_1 = require("./well-known-keys");
11
11
  const _CACHE = {};
12
12
  const getCache = (uid) => {
13
13
  if (!_CACHE[uid]) {
@@ -43,48 +43,52 @@ const decodeKey = (meta, block, key) => {
43
43
  };
44
44
  exports.decodeKey = decodeKey;
45
45
  const decodeKeyValue = (meta, block, key, value, toHuman = true) => {
46
+ const res = (0, well_known_keys_1.decodeWellKnownKey)(meta.registry, key, value);
47
+ if (res) {
48
+ return {
49
+ section: 'substrate',
50
+ method: res.name,
51
+ key: res.key,
52
+ value: res.value,
53
+ };
54
+ }
46
55
  const { storage, decodedKey } = (0, exports.decodeKey)(meta, block, key);
47
56
  if (!storage || !decodedKey) {
48
- return { [key]: value };
57
+ return undefined;
49
58
  }
50
59
  const decodeValue = () => {
51
60
  if (!value)
52
61
  return null;
53
- if (storage.section === 'substrate' && storage.method === 'code') {
54
- return `:code blake2_256 ${(0, util_crypto_1.blake2AsHex)(value, 256)} (${(0, util_1.hexToU8a)(value).length} bytes)`;
55
- }
56
62
  return meta.registry.createType(decodedKey.outputType, (0, util_1.hexToU8a)(value))[toHuman ? 'toHuman' : 'toJSON']();
57
63
  };
58
- switch (decodedKey.args.length) {
59
- case 2: {
60
- return {
61
- [storage.section]: {
62
- [storage.method]: {
63
- [decodedKey.args[0].toString()]: {
64
- [decodedKey.args[1].toString()]: decodeValue(),
65
- },
66
- },
67
- },
68
- };
69
- }
70
- case 1: {
71
- return {
72
- [storage.section]: {
73
- [storage.method]: {
74
- [decodedKey.args[0].toString()]: decodeValue(),
75
- },
76
- },
77
- };
64
+ return {
65
+ section: storage.section,
66
+ method: storage.method,
67
+ key: decodedKey.args,
68
+ value: decodeValue(),
69
+ };
70
+ };
71
+ exports.decodeKeyValue = decodeKeyValue;
72
+ const toStorageObject = (decoded) => {
73
+ if (!decoded) {
74
+ return undefined;
75
+ }
76
+ const { section, method, key, value } = decoded;
77
+ let obj = value;
78
+ if (key) {
79
+ for (let i = key.length - 1; i >= 0; i--) {
80
+ const k = key[i];
81
+ const newObj = { [k.toString()]: obj };
82
+ obj = newObj;
78
83
  }
79
- default:
80
- return {
81
- [storage.section]: {
82
- [storage.method]: decodeValue(),
83
- },
84
- };
85
84
  }
85
+ return {
86
+ [section]: {
87
+ [method]: obj,
88
+ },
89
+ };
86
90
  };
87
- exports.decodeKeyValue = decodeKeyValue;
91
+ exports.toStorageObject = toStorageObject;
88
92
  /**
89
93
  * Decode block storage diff
90
94
  * @param block Block to compare storage diff
@@ -96,8 +100,11 @@ const decodeBlockStorageDiff = async (block, diff) => {
96
100
  const newState = {};
97
101
  const meta = await block.meta;
98
102
  for (const [key, value] of diff) {
99
- lodash_1.default.merge(oldState, (0, exports.decodeKeyValue)(meta, block, key, (await block.get(key))));
100
- lodash_1.default.merge(newState, (0, exports.decodeKeyValue)(meta, block, key, value));
103
+ const oldValue = await block.get(key);
104
+ const oldDecoded = (0, exports.toStorageObject)((0, exports.decodeKeyValue)(meta, block, key, oldValue)) ?? { [key]: oldValue };
105
+ lodash_1.default.merge(oldState, oldDecoded);
106
+ const newDecoded = (0, exports.toStorageObject)((0, exports.decodeKeyValue)(meta, block, key, value)) ?? { [key]: value };
107
+ lodash_1.default.merge(newState, newDecoded);
101
108
  }
102
109
  return [oldState, newState];
103
110
  };
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.printRuntimeLogs = exports.stripChildPrefix = exports.splitChildKey = exports.isPrefixedChildKey = exports.prefixedChildKey = exports.defer = exports.isUrl = exports.getParaId = exports.compactHex = exports.fetchKeysToArray = exports.fetchKeys = void 0;
17
+ exports.printRuntimeLogs = exports.formatRuntimeLog = exports.stripChildPrefix = exports.splitChildKey = exports.isPrefixedChildKey = exports.prefixedChildKey = exports.defer = exports.isUrl = exports.getParaId = exports.compactHex = exports.fetchKeysToArray = exports.fetchKeys = void 0;
18
18
  const util_1 = require("@polkadot/util");
19
19
  const hex_1 = require("@polkadot/util/hex");
20
20
  __exportStar(require("./set-storage"), exports);
@@ -107,12 +107,25 @@ const stripChildPrefix = (key) => {
107
107
  return storageKey;
108
108
  };
109
109
  exports.stripChildPrefix = stripChildPrefix;
110
+ const logLevels = ['OFF', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'];
111
+ const formatRuntimeLog = (log) => {
112
+ let msg = '';
113
+ if (log.level != null) {
114
+ msg += `${logLevels[log.level]}\t `;
115
+ }
116
+ if (log.target) {
117
+ msg += `[${log.target}]:\t `;
118
+ }
119
+ msg += log.message;
120
+ return msg;
121
+ };
122
+ exports.formatRuntimeLog = formatRuntimeLog;
110
123
  const printRuntimeLogs = (logs) => {
111
124
  if (!logs.length)
112
125
  return;
113
126
  console.group('RuntimeLogs:');
114
127
  for (const log of logs) {
115
- console.log(log);
128
+ console.log((0, exports.formatRuntimeLog)(log));
116
129
  }
117
130
  console.groupEnd();
118
131
  };
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decodeWellKnownKey = void 0;
4
+ const util_crypto_1 = require("@polkadot/util-crypto");
5
+ const util_1 = require("@polkadot/util");
6
+ const decodeValue = (type) => (registry, value) => {
7
+ return registry.createType(type, (0, util_1.hexToU8a)(value)).toJSON();
8
+ };
9
+ // https://github.com/paritytech/polkadot-sdk/issues/2126
10
+ const wellKnownKeys = [
11
+ {
12
+ name: 'code',
13
+ key: ':code',
14
+ decodeValue: (_registry, value) => {
15
+ return `<:code blake2_256 ${(0, util_crypto_1.blake2AsHex)(value, 256)} (${value.length / 2 - 1} bytes)>`;
16
+ },
17
+ },
18
+ {
19
+ name: 'heapPages',
20
+ key: ':heappages',
21
+ type: 'u64',
22
+ },
23
+ {
24
+ name: 'extrinsicIndex',
25
+ key: ':extrinsic_index',
26
+ type: 'u32',
27
+ },
28
+ {
29
+ name: 'intrablockEntropy',
30
+ key: ':intrablock_entropy',
31
+ type: '[u8; 32]',
32
+ },
33
+ {
34
+ name: 'transactionLevel',
35
+ key: ':transaction_level:',
36
+ type: 'u32',
37
+ },
38
+ {
39
+ name: 'grandpaAuthorities',
40
+ key: ':grandpa_authorities',
41
+ type: '(u8, AuthorityList)',
42
+ },
43
+ {
44
+ name: 'relayDispatchQueueRemainingCapacity',
45
+ prefix: ':relay_dispatch_queue_remaining_capacity',
46
+ decodeKey: (registry, key) => {
47
+ return [registry.createType('u32', (0, util_1.hexToU8a)(key)).toJSON()];
48
+ },
49
+ type: '(u32, u32)',
50
+ },
51
+ ].map((def) => {
52
+ const prefix = (0, util_1.stringToHex)(def.prefix || def.key);
53
+ return {
54
+ name: def.name,
55
+ prefix,
56
+ decodeKey: def.decodeKey || ((_registry, key) => [key]),
57
+ decodeValue: def.decodeValue || decodeValue(def.type),
58
+ };
59
+ });
60
+ const decodeWellKnownKey = (registry, key, value) => {
61
+ for (const defs of wellKnownKeys) {
62
+ if (key.startsWith(defs.prefix)) {
63
+ const remaining = key.slice(defs.prefix.length);
64
+ const decodedKey = remaining ? defs.decodeKey(registry, `0x${remaining}`) : undefined;
65
+ const decodedValue = value ? defs.decodeValue(registry, value) : undefined;
66
+ return {
67
+ name: defs.name,
68
+ key: decodedKey ?? [],
69
+ value: decodedValue,
70
+ };
71
+ }
72
+ }
73
+ };
74
+ exports.decodeWellKnownKey = decodeWellKnownKey;
@@ -7,10 +7,41 @@ exports.startWorker = void 0;
7
7
  const comlink_1 = require("comlink");
8
8
  const node_adapter_js_1 = __importDefault(require("comlink/dist/umd/node-adapter.js"));
9
9
  const node_worker_threads_1 = __importDefault(require("node:worker_threads"));
10
- const node_url_1 = __importDefault(require("node:url"));
11
10
  const startWorker = async () => {
12
- const worker = new node_worker_threads_1.default.Worker(node_url_1.default.resolve(__filename, 'node-wasm-executor.mjs'), {
11
+ const workerCode = `
12
+ const Comlink = require('comlink')
13
+ const pkg = require('@acala-network/chopsticks-executor')
14
+ const { parentPort } = require('node:worker_threads')
15
+ const nodeEndpoint = require('comlink/dist/umd/node-adapter.js')
16
+
17
+ const getRuntimeVersion = async (code) => {
18
+ return pkg.get_runtime_version(code)
19
+ }
20
+
21
+ // trie_version: 0 for old trie, 1 for new trie
22
+ const calculateStateRoot = async (entries, trie_version) => {
23
+ return pkg.calculate_state_root(entries, trie_version)
24
+ }
25
+
26
+ const decodeProof = async (trieRootHash, keys, nodes) => {
27
+ return pkg.decode_proof(trieRootHash, keys, nodes)
28
+ }
29
+
30
+ const createProof = async (nodes, entries) => {
31
+ return pkg.create_proof(nodes, entries)
32
+ }
33
+
34
+ const runTask = async (task, callback) => {
35
+ return pkg.run_task(task, callback, process.env.RUST_LOG)
36
+ }
37
+
38
+ const wasmExecutor = { runTask, getRuntimeVersion, calculateStateRoot, createProof, decodeProof }
39
+
40
+ Comlink.expose(wasmExecutor, nodeEndpoint(parentPort))
41
+ `;
42
+ const worker = new node_worker_threads_1.default.Worker(workerCode, {
13
43
  name: 'chopsticks-wasm-executor',
44
+ eval: true,
14
45
  });
15
46
  return {
16
47
  remote: (0, comlink_1.wrap)((0, node_adapter_js_1.default)(worker)),
package/dist/esm/api.js CHANGED
@@ -121,5 +121,17 @@ export class Api {
121
121
  return __classPrivateFieldGet(this, _Api_provider, "f").send('state_getKeysPaged', params, !!hash);
122
122
  }
123
123
  }
124
+ async subscribeRemoteNewHeads(cb) {
125
+ if (!__classPrivateFieldGet(this, _Api_provider, "f").hasSubscriptions) {
126
+ throw new Error('subscribeRemoteNewHeads only works with subscriptions');
127
+ }
128
+ return __classPrivateFieldGet(this, _Api_provider, "f").subscribe('chain_newHead', 'chain_subscribeNewHeads', [], cb);
129
+ }
130
+ async subscribeRemoteFinalizedHeads(cb) {
131
+ if (!__classPrivateFieldGet(this, _Api_provider, "f").hasSubscriptions) {
132
+ throw new Error('subscribeRemoteFinalizedHeads only works with subscriptions');
133
+ }
134
+ return __classPrivateFieldGet(this, _Api_provider, "f").subscribe('chain_finalizedHead', 'chain_subscribeFinalizedHeads', [], cb);
135
+ }
124
136
  }
125
137
  _Api_provider = new WeakMap(), _Api_ready = new WeakMap(), _Api_chain = new WeakMap(), _Api_chainProperties = new WeakMap();
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
12
  var _TxPool_instances, _TxPool_chain, _TxPool_pool, _TxPool_ump, _TxPool_dmp, _TxPool_hrmp, _TxPool_mode, _TxPool_inherentProvider, _TxPool_pendingBlocks, _TxPool_isBuilding, _TxPool_getSigner, _TxPool_maybeBuildBlock, _TxPool_batchBuildBlock, _TxPool_buildBlockIfNeeded, _TxPool_buildBlock;
13
- import { EventEmitter } from 'eventemitter3';
13
+ import { default as EventEmitter } from 'eventemitter3';
14
14
  import _ from 'lodash';
15
15
  import { defer } from '../utils';
16
16
  import { buildBlock } from './block-builder';
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
12
  var _a, _ChopsticksProvider_isConnected, _ChopsticksProvider_eventemitter, _ChopsticksProvider_isReadyPromise, _ChopsticksProvider_subscriptions;
13
- import { EventEmitter } from 'eventemitter3';
13
+ import { default as EventEmitter } from 'eventemitter3';
14
14
  import { allHandlers } from './rpc';
15
15
  import { defaultLogger } from './logger';
16
16
  import { setup } from './setup';
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
12
  var _GenesisProvider_isConnected, _GenesisProvider_eventemitter, _GenesisProvider_isReadyPromise, _GenesisProvider_genesis, _GenesisProvider_stateRoot;
13
- import { EventEmitter } from 'eventemitter3';
13
+ import { default as EventEmitter } from 'eventemitter3';
14
14
  import { genesisSchema } from './schema';
15
15
  import { calculateStateRoot, emptyTaskHandler } from './wasm-executor';
16
16
  /**
@@ -0,0 +1 @@
1
+ {"type": "module"}
@@ -1,7 +1,7 @@
1
1
  import '@polkadot/types-codec';
2
- import { blake2AsHex } from '@polkadot/util-crypto';
3
2
  import { hexToU8a, u8aToHex } from '@polkadot/util';
4
3
  import _ from 'lodash';
4
+ import { decodeWellKnownKey } from './well-known-keys';
5
5
  const _CACHE = {};
6
6
  const getCache = (uid) => {
7
7
  if (!_CACHE[uid]) {
@@ -36,46 +36,49 @@ export const decodeKey = (meta, block, key) => {
36
36
  return {};
37
37
  };
38
38
  export const decodeKeyValue = (meta, block, key, value, toHuman = true) => {
39
+ const res = decodeWellKnownKey(meta.registry, key, value);
40
+ if (res) {
41
+ return {
42
+ section: 'substrate',
43
+ method: res.name,
44
+ key: res.key,
45
+ value: res.value,
46
+ };
47
+ }
39
48
  const { storage, decodedKey } = decodeKey(meta, block, key);
40
49
  if (!storage || !decodedKey) {
41
- return { [key]: value };
50
+ return undefined;
42
51
  }
43
52
  const decodeValue = () => {
44
53
  if (!value)
45
54
  return null;
46
- if (storage.section === 'substrate' && storage.method === 'code') {
47
- return `:code blake2_256 ${blake2AsHex(value, 256)} (${hexToU8a(value).length} bytes)`;
48
- }
49
55
  return meta.registry.createType(decodedKey.outputType, hexToU8a(value))[toHuman ? 'toHuman' : 'toJSON']();
50
56
  };
51
- switch (decodedKey.args.length) {
52
- case 2: {
53
- return {
54
- [storage.section]: {
55
- [storage.method]: {
56
- [decodedKey.args[0].toString()]: {
57
- [decodedKey.args[1].toString()]: decodeValue(),
58
- },
59
- },
60
- },
61
- };
62
- }
63
- case 1: {
64
- return {
65
- [storage.section]: {
66
- [storage.method]: {
67
- [decodedKey.args[0].toString()]: decodeValue(),
68
- },
69
- },
70
- };
57
+ return {
58
+ section: storage.section,
59
+ method: storage.method,
60
+ key: decodedKey.args,
61
+ value: decodeValue(),
62
+ };
63
+ };
64
+ export const toStorageObject = (decoded) => {
65
+ if (!decoded) {
66
+ return undefined;
67
+ }
68
+ const { section, method, key, value } = decoded;
69
+ let obj = value;
70
+ if (key) {
71
+ for (let i = key.length - 1; i >= 0; i--) {
72
+ const k = key[i];
73
+ const newObj = { [k.toString()]: obj };
74
+ obj = newObj;
71
75
  }
72
- default:
73
- return {
74
- [storage.section]: {
75
- [storage.method]: decodeValue(),
76
- },
77
- };
78
76
  }
77
+ return {
78
+ [section]: {
79
+ [method]: obj,
80
+ },
81
+ };
79
82
  };
80
83
  /**
81
84
  * Decode block storage diff
@@ -88,8 +91,11 @@ export const decodeBlockStorageDiff = async (block, diff) => {
88
91
  const newState = {};
89
92
  const meta = await block.meta;
90
93
  for (const [key, value] of diff) {
91
- _.merge(oldState, decodeKeyValue(meta, block, key, (await block.get(key))));
92
- _.merge(newState, decodeKeyValue(meta, block, key, value));
94
+ const oldValue = await block.get(key);
95
+ const oldDecoded = toStorageObject(decodeKeyValue(meta, block, key, oldValue)) ?? { [key]: oldValue };
96
+ _.merge(oldState, oldDecoded);
97
+ const newDecoded = toStorageObject(decodeKeyValue(meta, block, key, value)) ?? { [key]: value };
98
+ _.merge(newState, newDecoded);
93
99
  }
94
100
  return [oldState, newState];
95
101
  };
@@ -80,12 +80,24 @@ export const stripChildPrefix = (key) => {
80
80
  return key;
81
81
  return storageKey;
82
82
  };
83
+ const logLevels = ['OFF', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'];
84
+ export const formatRuntimeLog = (log) => {
85
+ let msg = '';
86
+ if (log.level != null) {
87
+ msg += `${logLevels[log.level]}\t `;
88
+ }
89
+ if (log.target) {
90
+ msg += `[${log.target}]:\t `;
91
+ }
92
+ msg += log.message;
93
+ return msg;
94
+ };
83
95
  export const printRuntimeLogs = (logs) => {
84
96
  if (!logs.length)
85
97
  return;
86
98
  console.group('RuntimeLogs:');
87
99
  for (const log of logs) {
88
- console.log(log);
100
+ console.log(formatRuntimeLog(log));
89
101
  }
90
102
  console.groupEnd();
91
103
  };
@@ -0,0 +1,70 @@
1
+ import { blake2AsHex } from '@polkadot/util-crypto';
2
+ import { hexToU8a, stringToHex } from '@polkadot/util';
3
+ const decodeValue = (type) => (registry, value) => {
4
+ return registry.createType(type, hexToU8a(value)).toJSON();
5
+ };
6
+ // https://github.com/paritytech/polkadot-sdk/issues/2126
7
+ const wellKnownKeys = [
8
+ {
9
+ name: 'code',
10
+ key: ':code',
11
+ decodeValue: (_registry, value) => {
12
+ return `<:code blake2_256 ${blake2AsHex(value, 256)} (${value.length / 2 - 1} bytes)>`;
13
+ },
14
+ },
15
+ {
16
+ name: 'heapPages',
17
+ key: ':heappages',
18
+ type: 'u64',
19
+ },
20
+ {
21
+ name: 'extrinsicIndex',
22
+ key: ':extrinsic_index',
23
+ type: 'u32',
24
+ },
25
+ {
26
+ name: 'intrablockEntropy',
27
+ key: ':intrablock_entropy',
28
+ type: '[u8; 32]',
29
+ },
30
+ {
31
+ name: 'transactionLevel',
32
+ key: ':transaction_level:',
33
+ type: 'u32',
34
+ },
35
+ {
36
+ name: 'grandpaAuthorities',
37
+ key: ':grandpa_authorities',
38
+ type: '(u8, AuthorityList)',
39
+ },
40
+ {
41
+ name: 'relayDispatchQueueRemainingCapacity',
42
+ prefix: ':relay_dispatch_queue_remaining_capacity',
43
+ decodeKey: (registry, key) => {
44
+ return [registry.createType('u32', hexToU8a(key)).toJSON()];
45
+ },
46
+ type: '(u32, u32)',
47
+ },
48
+ ].map((def) => {
49
+ const prefix = stringToHex(def.prefix || def.key);
50
+ return {
51
+ name: def.name,
52
+ prefix,
53
+ decodeKey: def.decodeKey || ((_registry, key) => [key]),
54
+ decodeValue: def.decodeValue || decodeValue(def.type),
55
+ };
56
+ });
57
+ export const decodeWellKnownKey = (registry, key, value) => {
58
+ for (const defs of wellKnownKeys) {
59
+ if (key.startsWith(defs.prefix)) {
60
+ const remaining = key.slice(defs.prefix.length);
61
+ const decodedKey = remaining ? defs.decodeKey(registry, `0x${remaining}`) : undefined;
62
+ const decodedValue = value ? defs.decodeValue(registry, value) : undefined;
63
+ return {
64
+ name: defs.name,
65
+ key: decodedKey ?? [],
66
+ value: decodedValue,
67
+ };
68
+ }
69
+ }
70
+ };
@@ -1,10 +1,41 @@
1
1
  import { wrap } from 'comlink';
2
2
  import nodeEndpoint from 'comlink/dist/umd/node-adapter.js';
3
3
  import threads from 'node:worker_threads';
4
- import url from 'node:url';
5
4
  export const startWorker = async () => {
6
- const worker = new threads.Worker(url.resolve(__filename, 'node-wasm-executor.mjs'), {
5
+ const workerCode = `
6
+ const Comlink = require('comlink')
7
+ const pkg = require('@acala-network/chopsticks-executor')
8
+ const { parentPort } = require('node:worker_threads')
9
+ const nodeEndpoint = require('comlink/dist/umd/node-adapter.js')
10
+
11
+ const getRuntimeVersion = async (code) => {
12
+ return pkg.get_runtime_version(code)
13
+ }
14
+
15
+ // trie_version: 0 for old trie, 1 for new trie
16
+ const calculateStateRoot = async (entries, trie_version) => {
17
+ return pkg.calculate_state_root(entries, trie_version)
18
+ }
19
+
20
+ const decodeProof = async (trieRootHash, keys, nodes) => {
21
+ return pkg.decode_proof(trieRootHash, keys, nodes)
22
+ }
23
+
24
+ const createProof = async (nodes, entries) => {
25
+ return pkg.create_proof(nodes, entries)
26
+ }
27
+
28
+ const runTask = async (task, callback) => {
29
+ return pkg.run_task(task, callback, process.env.RUST_LOG)
30
+ }
31
+
32
+ const wasmExecutor = { runTask, getRuntimeVersion, calculateStateRoot, createProof, decodeProof }
33
+
34
+ Comlink.expose(wasmExecutor, nodeEndpoint(parentPort))
35
+ `;
36
+ const worker = new threads.Worker(workerCode, {
7
37
  name: 'chopsticks-wasm-executor',
38
+ eval: true,
8
39
  });
9
40
  return {
10
41
  remote: wrap(nodeEndpoint(worker)),
@@ -1,6 +1,6 @@
1
1
  import { ExtDef } from '@polkadot/types/extrinsic/signedExtensions/types';
2
2
  import { HexString } from '@polkadot/util/types';
3
- import { ProviderInterface } from '@polkadot/rpc-provider/types';
3
+ import { ProviderInterface, ProviderInterfaceCallback } from '@polkadot/rpc-provider/types';
4
4
  export type ChainProperties = {
5
5
  ss58Format?: number;
6
6
  tokenDecimals?: number[];
@@ -50,5 +50,7 @@ export declare class Api {
50
50
  getBlock(hash?: string): Promise<SignedBlock | null>;
51
51
  getStorage(key: string, hash?: string): Promise<`0x${string}` | null>;
52
52
  getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string): Promise<string[]>;
53
+ subscribeRemoteNewHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
54
+ subscribeRemoteFinalizedHeads(cb: ProviderInterfaceCallback): Promise<string | number>;
53
55
  }
54
56
  export {};
@@ -1,6 +1,7 @@
1
1
  import { Header, TransactionValidityError } from '@polkadot/types/interfaces';
2
- import { Block, TaskCallResponse } from './block';
2
+ import { Block } from './block';
3
3
  import { HexString } from '@polkadot/util/types';
4
+ import { TaskCallResponse } from '../wasm-executor';
4
5
  export declare const newHeader: (head: Block, unsafeBlockHeight?: number) => Promise<Header>;
5
6
  export type BuildBlockCallbacks = {
6
7
  onApplyExtrinsicError?: (extrinsic: HexString, error: TransactionValidityError) => void;
@@ -5,13 +5,7 @@ import { StorageEntry } from '@polkadot/types/primitive/types';
5
5
  import type { HexString } from '@polkadot/util/types';
6
6
  import { Blockchain } from '.';
7
7
  import { StorageLayer, StorageLayerProvider, StorageValue } from './storage-layer';
8
- import type { RuntimeVersion } from '../wasm-executor';
9
- export type TaskCallResponse = {
10
- result: HexString;
11
- storageDiff: [HexString, HexString | null][];
12
- offchainStorageDiff: [HexString, HexString | null][];
13
- runtimeLogs: string[];
14
- };
8
+ import type { RuntimeVersion, TaskCallResponse } from '../wasm-executor';
15
9
  /**
16
10
  * Block class.
17
11
  *
@@ -53,7 +47,7 @@ export declare class Block {
53
47
  /**
54
48
  * Get the block storage by key.
55
49
  */
56
- get(key: string): Promise<string | undefined>;
50
+ get(key: string): Promise<HexString | undefined>;
57
51
  read<T extends string>(type: T, query: StorageEntry, ...args: any[]): Promise<import("@polkadot/types/types").DetectCodec<import("@polkadot/types-codec/types").Codec, T> | undefined>;
58
52
  /**
59
53
  * Get paged storage keys.
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from 'eventemitter3';
1
+ import { default as EventEmitter } from 'eventemitter3';
2
2
  import { HexString } from '@polkadot/util/types';
3
3
  import { Blockchain } from '.';
4
4
  import { InherentProvider } from './inherent';
@@ -9,12 +9,16 @@ export declare const decodeKey: (meta: DecoratedMeta, block: Block, key: HexStri
9
9
  decodedKey?: StorageKey<import("@polkadot/types-codec/types").AnyTuple> | undefined;
10
10
  };
11
11
  export declare const decodeKeyValue: (meta: DecoratedMeta, block: Block, key: HexString, value?: HexString | null, toHuman?: boolean) => {
12
- [x: string]: `0x${string}` | null | undefined;
13
- } | {
12
+ section: string;
13
+ method: string;
14
+ key: any[];
15
+ value: import("@polkadot/types-codec/types").AnyJson;
16
+ } | undefined;
17
+ export declare const toStorageObject: (decoded: ReturnType<typeof decodeKeyValue>) => {
14
18
  [x: string]: {
15
19
  [x: string]: import("@polkadot/types-codec/types").AnyJson;
16
20
  };
17
- };
21
+ } | undefined;
18
22
  /**
19
23
  * Decode block storage diff
20
24
  * @param block Block to compare storage diff
@@ -1,6 +1,7 @@
1
1
  import { HexString } from '@polkadot/util/types';
2
2
  import { StorageKey } from '@polkadot/types';
3
3
  import { Blockchain } from '../blockchain';
4
+ import { RuntimeLog } from '../wasm-executor';
4
5
  export * from './set-storage';
5
6
  export * from './time-travel';
6
7
  export * from './decoder';
@@ -21,4 +22,5 @@ export declare const prefixedChildKey: (prefix: HexString, key: HexString) => st
21
22
  export declare const isPrefixedChildKey: (key: HexString) => boolean;
22
23
  export declare const splitChildKey: (key: HexString) => never[] | [`0x${string}`, `0x${string}`];
23
24
  export declare const stripChildPrefix: (key: HexString) => `0x${string}`;
24
- export declare const printRuntimeLogs: (logs: string[]) => void;
25
+ export declare const formatRuntimeLog: (log: RuntimeLog) => string;
26
+ export declare const printRuntimeLogs: (logs: RuntimeLog[]) => void;
@@ -0,0 +1,7 @@
1
+ import { HexString } from '@polkadot/util/types';
2
+ import { Registry } from '@polkadot/types-codec/types';
3
+ export declare const decodeWellKnownKey: (registry: Registry, key: HexString, value?: HexString | null) => {
4
+ name: string;
5
+ key: any[];
6
+ value: import("@polkadot/types-codec/types").AnyJson;
7
+ } | undefined;
@@ -1,5 +1,4 @@
1
- import type { WasmExecutor } from '.';
2
- export declare const startWorker: () => Promise<{
3
- remote: import("comlink").Remote<WasmExecutor>;
1
+ export declare const startWorker: <T>() => Promise<{
2
+ remote: import("comlink").Remote<T>;
4
3
  terminate: () => Promise<void>;
5
4
  }>;
@@ -14,13 +14,19 @@ export type RuntimeVersion = {
14
14
  transactionVersion: number;
15
15
  stateVersion: number;
16
16
  };
17
+ export type RuntimeLog = {
18
+ message: string;
19
+ level?: number;
20
+ target?: string;
21
+ };
22
+ export type TaskCallResponse = {
23
+ result: HexString;
24
+ storageDiff: [HexString, HexString | null][];
25
+ offchainStorageDiff: [HexString, HexString | null][];
26
+ runtimeLogs: RuntimeLog[];
27
+ };
17
28
  export type TaskResponse = {
18
- Call: {
19
- result: HexString;
20
- storageDiff: [HexString, HexString | null][];
21
- offchainStorageDiff: [HexString, HexString | null][];
22
- runtimeLogs: string[];
23
- };
29
+ Call: TaskCallResponse;
24
30
  } | {
25
31
  Error: string;
26
32
  };
@@ -51,12 +57,7 @@ export declare const runTask: (task: {
51
57
  allowUnresolvedImports: boolean;
52
58
  runtimeLogLevel: number;
53
59
  }, callback?: JsCallback) => Promise<{
54
- Call: {
55
- result: HexString;
56
- storageDiff: [HexString, HexString | null][];
57
- offchainStorageDiff: [HexString, HexString | null][];
58
- runtimeLogs: string[];
59
- };
60
+ Call: TaskCallResponse;
60
61
  } | {
61
62
  Error: string;
62
63
  }>;
@@ -1,5 +1,4 @@
1
- import type { WasmExecutor } from '.';
2
- export declare const startWorker: () => Promise<{
3
- remote: import("comlink").Remote<WasmExecutor>;
1
+ export declare const startWorker: <T>() => Promise<{
2
+ remote: import("comlink").Remote<T>;
4
3
  terminate: () => Promise<void>;
5
4
  }>;
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks-core",
3
- "version": "0.9.0",
3
+ "version": "0.9.1-2",
4
4
  "author": "Acala Developers <hello@acala.network>",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
7
7
  "clean": "rm -rf dist",
8
- "build": "yarn clean && tsc -p ./tsconfig.json && tsc -p ./tsconfig.esm.json && yarn copyfiles",
8
+ "build": "yarn clean && tsc -p ./tsconfig.json && tsc -p ./tsconfig.esm.json && echo '{\"type\": \"module\"}' > ./dist/esm/package.json && yarn copyfiles",
9
9
  "copyfiles": "cp -r src/wasm-executor/*.mjs dist/cjs/wasm-executor/ && cp -r src/wasm-executor/*.mjs dist/esm/wasm-executor/",
10
10
  "docs:prep": "typedoc"
11
11
  },
12
12
  "dependencies": {
13
- "@acala-network/chopsticks-executor": "0.9.0",
13
+ "@acala-network/chopsticks-executor": "0.9.1-2",
14
14
  "@polkadot/api": "^10.10.1",
15
15
  "@polkadot/util-crypto": "^12.5.1",
16
16
  "comlink": "^4.4.1",
17
17
  "eventemitter3": "^5.0.1",
18
18
  "lodash": "^4.17.21",
19
- "pino": "^8.15.0",
19
+ "pino": "^8.16.1",
20
20
  "pino-pretty": "^10.2.0",
21
21
  "zod": "^3.22.3"
22
22
  },
@@ -45,12 +45,11 @@
45
45
  "import": "./dist/esm/index.js",
46
46
  "default": "./dist/esm/index.js"
47
47
  },
48
- "./package.json": "./package.json"
48
+ "./package.json": "./package.json",
49
+ "./package.esm.json": "./dist/esm/package.json"
49
50
  },
50
51
  "browser": {
51
- "./dist/cjs/wasm-executor/node-wasm-executor.mjs": "./dist/cjs/wasm-executor/browser-wasm-executor.mjs",
52
52
  "./dist/cjs/wasm-executor/node-worker.js": "./dist/cjs/wasm-executor/browser-worker.js",
53
- "./dist/esm/wasm-executor/node-wasm-executor.mjs": "./dist/esm/wasm-executor/browser-wasm-executor.mjs",
54
53
  "./dist/esm/wasm-executor/node-worker.js": "./dist/esm/wasm-executor/browser-worker.js"
55
54
  }
56
55
  }
@@ -1,29 +0,0 @@
1
- import * as Comlink from 'comlink'
2
- import * as pkg from '@acala-network/chopsticks-executor'
3
- import { parentPort } from 'node:worker_threads'
4
- import nodeEndpoint from 'comlink/dist/umd/node-adapter.js'
5
-
6
- const getRuntimeVersion = async (code) => {
7
- return pkg.get_runtime_version(code)
8
- }
9
-
10
- // trie_version: 0 for old trie, 1 for new trie
11
- const calculateStateRoot = async (entries, trie_version) => {
12
- return pkg.calculate_state_root(entries, trie_version)
13
- }
14
-
15
- const decodeProof = async (trieRootHash, keys, nodes) => {
16
- return pkg.decode_proof(trieRootHash, keys, nodes)
17
- }
18
-
19
- const createProof = async (nodes, entries) => {
20
- return pkg.create_proof(nodes, entries)
21
- }
22
-
23
- const runTask = async (task, callback) => {
24
- return pkg.run_task(task, callback, process.env.RUST_LOG)
25
- }
26
-
27
- const wasmExecutor = { runTask, getRuntimeVersion, calculateStateRoot, createProof, decodeProof }
28
-
29
- Comlink.expose(wasmExecutor, nodeEndpoint(parentPort))
@@ -1,29 +0,0 @@
1
- import * as Comlink from 'comlink'
2
- import * as pkg from '@acala-network/chopsticks-executor'
3
- import { parentPort } from 'node:worker_threads'
4
- import nodeEndpoint from 'comlink/dist/umd/node-adapter.js'
5
-
6
- const getRuntimeVersion = async (code) => {
7
- return pkg.get_runtime_version(code)
8
- }
9
-
10
- // trie_version: 0 for old trie, 1 for new trie
11
- const calculateStateRoot = async (entries, trie_version) => {
12
- return pkg.calculate_state_root(entries, trie_version)
13
- }
14
-
15
- const decodeProof = async (trieRootHash, keys, nodes) => {
16
- return pkg.decode_proof(trieRootHash, keys, nodes)
17
- }
18
-
19
- const createProof = async (nodes, entries) => {
20
- return pkg.create_proof(nodes, entries)
21
- }
22
-
23
- const runTask = async (task, callback) => {
24
- return pkg.run_task(task, callback, process.env.RUST_LOG)
25
- }
26
-
27
- const wasmExecutor = { runTask, getRuntimeVersion, calculateStateRoot, createProof, decodeProof }
28
-
29
- Comlink.expose(wasmExecutor, nodeEndpoint(parentPort))