@acala-network/chopsticks-core 0.8.5-5 → 0.9.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 (128) hide show
  1. package/{lib → dist/cjs}/api.js +7 -7
  2. package/{lib → dist/cjs}/blockchain/block.js +1 -4
  3. package/{lib → dist/cjs}/genesis-provider.js +1 -1
  4. package/{lib → dist/cjs}/rpc/substrate/chain.js +1 -1
  5. package/{lib → dist/cjs}/utils/index.js +11 -1
  6. package/dist/esm/api.js +125 -0
  7. package/dist/esm/blockchain/block-builder.js +293 -0
  8. package/dist/esm/blockchain/block.js +277 -0
  9. package/dist/esm/blockchain/head-state.js +79 -0
  10. package/dist/esm/blockchain/index.js +413 -0
  11. package/dist/esm/blockchain/inherent/index.js +40 -0
  12. package/dist/esm/blockchain/inherent/para-enter.js +29 -0
  13. package/dist/esm/blockchain/inherent/parachain/babe-randomness.js +11 -0
  14. package/dist/esm/blockchain/inherent/parachain/nimbus-author-inherent.js +11 -0
  15. package/dist/esm/blockchain/inherent/parachain/validation-data.js +165 -0
  16. package/dist/esm/blockchain/storage-layer.js +215 -0
  17. package/dist/esm/blockchain/txpool.js +208 -0
  18. package/dist/esm/chopsticks-provider.js +156 -0
  19. package/dist/esm/database.js +1 -0
  20. package/dist/esm/genesis-provider.js +144 -0
  21. package/dist/esm/logger.js +34 -0
  22. package/dist/esm/offchain.js +36 -0
  23. package/dist/esm/rpc/index.js +10 -0
  24. package/dist/esm/rpc/shared.js +15 -0
  25. package/dist/esm/rpc/substrate/author.js +85 -0
  26. package/dist/esm/rpc/substrate/chain.js +84 -0
  27. package/dist/esm/rpc/substrate/index.js +18 -0
  28. package/dist/esm/rpc/substrate/payment.js +40 -0
  29. package/dist/esm/rpc/substrate/state.js +166 -0
  30. package/dist/esm/rpc/substrate/system.js +48 -0
  31. package/dist/esm/schema/index.js +11 -0
  32. package/dist/esm/setup.js +71 -0
  33. package/dist/esm/utils/decoder.js +95 -0
  34. package/dist/esm/utils/index.js +91 -0
  35. package/dist/esm/utils/key-cache.js +61 -0
  36. package/dist/esm/utils/proof.js +33 -0
  37. package/dist/esm/utils/set-storage.js +56 -0
  38. package/dist/esm/utils/time-travel.js +58 -0
  39. package/dist/esm/wasm-executor/browser-wasm-executor.mjs +32 -0
  40. package/dist/esm/wasm-executor/browser-worker.js +15 -0
  41. package/dist/esm/wasm-executor/index.js +146 -0
  42. package/dist/esm/wasm-executor/node-wasm-executor.mjs +29 -0
  43. package/dist/esm/wasm-executor/node-worker.js +15 -0
  44. package/dist/esm/xcm/downward.js +25 -0
  45. package/dist/esm/xcm/horizontal.js +25 -0
  46. package/dist/esm/xcm/index.js +20 -0
  47. package/dist/esm/xcm/upward.js +17 -0
  48. package/{lib → dist/types}/genesis-provider.d.ts +2 -2
  49. package/dist/types/index.d.ts +28 -0
  50. package/{lib → dist/types}/utils/index.d.ts +1 -0
  51. package/package.json +23 -14
  52. /package/{lib → dist/cjs}/blockchain/block-builder.js +0 -0
  53. /package/{lib → dist/cjs}/blockchain/head-state.js +0 -0
  54. /package/{lib → dist/cjs}/blockchain/index.js +0 -0
  55. /package/{lib → dist/cjs}/blockchain/inherent/index.js +0 -0
  56. /package/{lib → dist/cjs}/blockchain/inherent/para-enter.js +0 -0
  57. /package/{lib → dist/cjs}/blockchain/inherent/parachain/babe-randomness.js +0 -0
  58. /package/{lib → dist/cjs}/blockchain/inherent/parachain/nimbus-author-inherent.js +0 -0
  59. /package/{lib → dist/cjs}/blockchain/inherent/parachain/validation-data.js +0 -0
  60. /package/{lib → dist/cjs}/blockchain/storage-layer.js +0 -0
  61. /package/{lib → dist/cjs}/blockchain/txpool.js +0 -0
  62. /package/{lib → dist/cjs}/chopsticks-provider.js +0 -0
  63. /package/{lib → dist/cjs}/database.js +0 -0
  64. /package/{lib → dist/cjs}/index.js +0 -0
  65. /package/{lib → dist/cjs}/logger.js +0 -0
  66. /package/{lib → dist/cjs}/offchain.js +0 -0
  67. /package/{lib → dist/cjs}/rpc/index.js +0 -0
  68. /package/{lib → dist/cjs}/rpc/shared.js +0 -0
  69. /package/{lib → dist/cjs}/rpc/substrate/author.js +0 -0
  70. /package/{lib → dist/cjs}/rpc/substrate/index.js +0 -0
  71. /package/{lib → dist/cjs}/rpc/substrate/payment.js +0 -0
  72. /package/{lib → dist/cjs}/rpc/substrate/state.js +0 -0
  73. /package/{lib → dist/cjs}/rpc/substrate/system.js +0 -0
  74. /package/{lib → dist/cjs}/schema/index.js +0 -0
  75. /package/{lib → dist/cjs}/setup.js +0 -0
  76. /package/{lib → dist/cjs}/utils/decoder.js +0 -0
  77. /package/{lib → dist/cjs}/utils/key-cache.js +0 -0
  78. /package/{lib → dist/cjs}/utils/proof.js +0 -0
  79. /package/{lib → dist/cjs}/utils/set-storage.js +0 -0
  80. /package/{lib → dist/cjs}/utils/time-travel.js +0 -0
  81. /package/{lib → dist/cjs}/wasm-executor/browser-wasm-executor.mjs +0 -0
  82. /package/{lib → dist/cjs}/wasm-executor/browser-worker.js +0 -0
  83. /package/{lib → dist/cjs}/wasm-executor/index.js +0 -0
  84. /package/{lib → dist/cjs}/wasm-executor/node-wasm-executor.mjs +0 -0
  85. /package/{lib → dist/cjs}/wasm-executor/node-worker.js +0 -0
  86. /package/{lib → dist/cjs}/xcm/downward.js +0 -0
  87. /package/{lib → dist/cjs}/xcm/horizontal.js +0 -0
  88. /package/{lib → dist/cjs}/xcm/index.js +0 -0
  89. /package/{lib → dist/cjs}/xcm/upward.js +0 -0
  90. /package/{lib/index.d.ts → dist/esm/index.js} +0 -0
  91. /package/{lib → dist/types}/api.d.ts +0 -0
  92. /package/{lib → dist/types}/blockchain/block-builder.d.ts +0 -0
  93. /package/{lib → dist/types}/blockchain/block.d.ts +0 -0
  94. /package/{lib → dist/types}/blockchain/head-state.d.ts +0 -0
  95. /package/{lib → dist/types}/blockchain/index.d.ts +0 -0
  96. /package/{lib → dist/types}/blockchain/inherent/index.d.ts +0 -0
  97. /package/{lib → dist/types}/blockchain/inherent/para-enter.d.ts +0 -0
  98. /package/{lib → dist/types}/blockchain/inherent/parachain/babe-randomness.d.ts +0 -0
  99. /package/{lib → dist/types}/blockchain/inherent/parachain/nimbus-author-inherent.d.ts +0 -0
  100. /package/{lib → dist/types}/blockchain/inherent/parachain/validation-data.d.ts +0 -0
  101. /package/{lib → dist/types}/blockchain/storage-layer.d.ts +0 -0
  102. /package/{lib → dist/types}/blockchain/txpool.d.ts +0 -0
  103. /package/{lib → dist/types}/chopsticks-provider.d.ts +0 -0
  104. /package/{lib → dist/types}/database.d.ts +0 -0
  105. /package/{lib → dist/types}/logger.d.ts +0 -0
  106. /package/{lib → dist/types}/offchain.d.ts +0 -0
  107. /package/{lib → dist/types}/rpc/index.d.ts +0 -0
  108. /package/{lib → dist/types}/rpc/shared.d.ts +0 -0
  109. /package/{lib → dist/types}/rpc/substrate/author.d.ts +0 -0
  110. /package/{lib → dist/types}/rpc/substrate/chain.d.ts +0 -0
  111. /package/{lib → dist/types}/rpc/substrate/index.d.ts +0 -0
  112. /package/{lib → dist/types}/rpc/substrate/payment.d.ts +0 -0
  113. /package/{lib → dist/types}/rpc/substrate/state.d.ts +0 -0
  114. /package/{lib → dist/types}/rpc/substrate/system.d.ts +0 -0
  115. /package/{lib → dist/types}/schema/index.d.ts +0 -0
  116. /package/{lib → dist/types}/setup.d.ts +0 -0
  117. /package/{lib → dist/types}/utils/decoder.d.ts +0 -0
  118. /package/{lib → dist/types}/utils/key-cache.d.ts +0 -0
  119. /package/{lib → dist/types}/utils/proof.d.ts +0 -0
  120. /package/{lib → dist/types}/utils/set-storage.d.ts +0 -0
  121. /package/{lib → dist/types}/utils/time-travel.d.ts +0 -0
  122. /package/{lib → dist/types}/wasm-executor/browser-worker.d.ts +0 -0
  123. /package/{lib → dist/types}/wasm-executor/index.d.ts +0 -0
  124. /package/{lib → dist/types}/wasm-executor/node-worker.d.ts +0 -0
  125. /package/{lib → dist/types}/xcm/downward.d.ts +0 -0
  126. /package/{lib → dist/types}/xcm/horizontal.d.ts +0 -0
  127. /package/{lib → dist/types}/xcm/index.d.ts +0 -0
  128. /package/{lib → dist/types}/xcm/upward.d.ts +0 -0
@@ -0,0 +1,166 @@
1
+ import { ResponseError } from '../shared';
2
+ import { defaultLogger } from '../../logger';
3
+ import { isPrefixedChildKey, prefixedChildKey, stripChildPrefix } from '../../utils';
4
+ const logger = defaultLogger.child({ name: 'rpc-state' });
5
+ /**
6
+ * @param context
7
+ * @param params - [`blockhash`]
8
+ *
9
+ * @return runtime version
10
+ */
11
+ export const state_getRuntimeVersion = async (context, [hash]) => {
12
+ const block = await context.chain.getBlock(hash);
13
+ return block?.runtimeVersion || null;
14
+ };
15
+ /**
16
+ * @param context
17
+ * @param params - [`blockhash`]
18
+ *
19
+ * @return metadata
20
+ */
21
+ export const state_getMetadata = async (context, [hash]) => {
22
+ const block = await context.chain.getBlock(hash);
23
+ return block?.metadata || null;
24
+ };
25
+ /**
26
+ * @param context
27
+ * @param params - [`key`, `blockhash`]
28
+ *
29
+ * @return storage value
30
+ */
31
+ export const state_getStorage = async (context, [key, hash]) => {
32
+ const block = await context.chain.getBlock(hash);
33
+ const value = (await block?.get(key)) || null;
34
+ return value || null;
35
+ };
36
+ /**
37
+ * @param context
38
+ * @param params - [`prefix`, `pageSize`, `startKey`, `blockhash`]
39
+ *
40
+ * @return paged keys
41
+ */
42
+ export const state_getKeysPaged = async (context, [prefix, pageSize, startKey, hash]) => {
43
+ const block = await context.chain.getBlock(hash);
44
+ return block?.getKeysPaged({ prefix, pageSize, startKey });
45
+ };
46
+ /**
47
+ * @param context
48
+ * @param params - [`keys`, `blockhash`]
49
+ *
50
+ * @return storage values
51
+ */
52
+ export const state_queryStorageAt = async (context, [keys, hash]) => {
53
+ const block = await context.chain.getBlock(hash);
54
+ if (!block) {
55
+ return [];
56
+ }
57
+ const values = await Promise.all(keys.map(async (key) => [key, await block.get(key).then((val) => val || null)]));
58
+ return [
59
+ {
60
+ block: block.hash,
61
+ changes: values,
62
+ },
63
+ ];
64
+ };
65
+ /**
66
+ * @param context
67
+ * @param params - [`method`, `data`, `blockhash`]
68
+ *
69
+ * @return result in hash
70
+ */
71
+ export const state_call = async (context, [method, data, hash]) => {
72
+ const block = await context.chain.getBlock(hash);
73
+ if (!block) {
74
+ throw new ResponseError(1, `Block ${hash} not found`);
75
+ }
76
+ const resp = await block.call(method, [data]);
77
+ return resp.result;
78
+ };
79
+ /**
80
+ * @return subscription id
81
+ */
82
+ export const state_subscribeRuntimeVersion = async (context, _params, { subscribe }) => {
83
+ let update = (_block) => { };
84
+ const id = await context.chain.headState.subscrubeRuntimeVersion((block) => update(block));
85
+ const callback = subscribe('state_runtimeVersion', id);
86
+ update = async (block) => callback(await block.runtimeVersion);
87
+ setTimeout(() => {
88
+ context.chain.head.runtimeVersion.then(callback);
89
+ }, 50);
90
+ return id;
91
+ };
92
+ /**
93
+ * @param context
94
+ * @param params - [`subid`]
95
+ * @param subscriptionManager
96
+ */
97
+ export const state_unsubscribeRuntimeVersion = async (_context, [subid], { unsubscribe }) => {
98
+ unsubscribe(subid);
99
+ };
100
+ /**
101
+ * @param context
102
+ * @param params - [`keys`]
103
+ * @param subscriptionManager
104
+ *
105
+ * @return subscription id
106
+ */
107
+ export const state_subscribeStorage = async (context, [keys], { subscribe }) => {
108
+ let update = (_block, _pairs) => { };
109
+ const id = await context.chain.headState.subscribeStorage(keys, (block, pairs) => update(block, pairs));
110
+ const callback = subscribe('state_storage', id, () => context.chain.headState.unsubscribeStorage(id));
111
+ update = async (block, pairs) => {
112
+ logger.trace({ hash: block.hash }, 'state_subscribeStorage');
113
+ callback({
114
+ block: block.hash,
115
+ changes: pairs,
116
+ });
117
+ };
118
+ (async () => {
119
+ const pairs = await Promise.all(keys.map(async (key) => {
120
+ const val = await context.chain.head.get(key);
121
+ return [key, val || null];
122
+ }));
123
+ callback({
124
+ block: context.chain.head.hash,
125
+ changes: pairs,
126
+ });
127
+ })();
128
+ return id;
129
+ };
130
+ /**
131
+ * @param context
132
+ * @param params - [`subid`]
133
+ * @param subscriptionManager
134
+ */
135
+ export const state_unsubscribeStorage = async (_context, [subid], { unsubscribe }) => {
136
+ unsubscribe(subid);
137
+ };
138
+ /**
139
+ * @param context
140
+ * @param params - [`child`, `key`, `blockhash`]
141
+ *
142
+ * @return storage valuse
143
+ */
144
+ export const childstate_getStorage = async (context, [child, key, hash]) => {
145
+ if (!isPrefixedChildKey(child)) {
146
+ throw new ResponseError(-32000, 'Client error: Invalid child storage key');
147
+ }
148
+ const block = await context.chain.getBlock(hash);
149
+ const value = await block?.get(prefixedChildKey(child, key));
150
+ return value || null;
151
+ };
152
+ /**
153
+ * @param context
154
+ * @param params - [`child`, `prefix`, `pageSize`, `startKey`, `blockhash`]
155
+ *
156
+ * @return paged keys
157
+ */
158
+ export const childstate_getKeysPaged = async (context, [child, prefix, pageSize, startKey, hash]) => {
159
+ if (!isPrefixedChildKey(child)) {
160
+ throw new ResponseError(-32000, 'Client error: Invalid child storage key');
161
+ }
162
+ const block = await context.chain.getBlock(hash);
163
+ return block
164
+ ?.getKeysPaged({ prefix: prefixedChildKey(child, prefix), pageSize, startKey: prefixedChildKey(child, startKey) })
165
+ .then((keys) => keys.map(stripChildPrefix));
166
+ };
@@ -0,0 +1,48 @@
1
+ import { hexToU8a } from '@polkadot/util';
2
+ export const system_localPeerId = async () => '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
3
+ export const system_nodeRoles = async () => ['Full'];
4
+ export const system_localListenAddresses = async () => [];
5
+ export const system_chain = async (context) => {
6
+ return context.chain.api.getSystemChain();
7
+ };
8
+ export const system_properties = async (context) => {
9
+ return context.chain.api.getSystemProperties();
10
+ };
11
+ export const system_name = async (context) => {
12
+ return context.chain.api.getSystemName();
13
+ };
14
+ export const system_version = async (_context) => {
15
+ return 'chopsticks-v1';
16
+ };
17
+ export const system_chainType = async (_context) => {
18
+ return 'Development';
19
+ };
20
+ export const system_health = async () => {
21
+ return {
22
+ peers: 0,
23
+ isSyncing: false,
24
+ shouldHavePeers: false,
25
+ };
26
+ };
27
+ /**
28
+ * @param context
29
+ * @param params - [`extrinsic`, `at`]
30
+ *
31
+ * @return ApplyExtrinsicResult (see `@polkadot/types/interfaces`) in hash
32
+ */
33
+ export const system_dryRun = async (context, [extrinsic, at]) => {
34
+ const { outcome } = await context.chain.dryRunExtrinsic(extrinsic, at);
35
+ return outcome.toHex();
36
+ };
37
+ /**
38
+ * @param context
39
+ * @param params - [`address`]
40
+ */
41
+ export const system_accountNextIndex = async (context, [address]) => {
42
+ const head = context.chain.head;
43
+ const registry = await head.registry;
44
+ const account = registry.createType('AccountId', address);
45
+ const result = await head.call('AccountNonceApi_account_nonce', [account.toHex()]);
46
+ const nonce = registry.createType('Index', hexToU8a(result.result)).toNumber();
47
+ return nonce + context.chain.txPool.pendingExtrinsicsBy(address).length;
48
+ };
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ export const genesisSchema = z.object({
3
+ id: z.string(),
4
+ name: z.string(),
5
+ properties: z.object({
6
+ ss58Format: z.number().optional(),
7
+ tokenDecimals: z.union([z.number(), z.array(z.number())]).optional(),
8
+ tokenSymbol: z.union([z.string(), z.array(z.string())]).optional(),
9
+ }),
10
+ genesis: z.object({ raw: z.object({ top: z.record(z.string()) }) }),
11
+ });
@@ -0,0 +1,71 @@
1
+ import '@polkadot/types-codec';
2
+ import { HttpProvider, WsProvider } from '@polkadot/rpc-provider';
3
+ import { Api } from './api';
4
+ import { Blockchain } from './blockchain';
5
+ import { InherentProviders, ParaInherentEnter, SetBabeRandomness, SetNimbusAuthorInherent, SetTimestamp, SetValidationData, } from './blockchain/inherent';
6
+ import { defaultLogger } from './logger';
7
+ export const setup = async (options) => {
8
+ let provider;
9
+ if (options.genesis) {
10
+ provider = options.genesis;
11
+ }
12
+ else if (/^(https|http):\/\//.test(options.endpoint || '')) {
13
+ provider = new HttpProvider(options.endpoint);
14
+ }
15
+ else {
16
+ provider = new WsProvider(options.endpoint);
17
+ }
18
+ const api = new Api(provider);
19
+ await api.isReady;
20
+ let blockHash;
21
+ if (options.block == null) {
22
+ blockHash = await api.getBlockHash().then((hash) => {
23
+ if (!hash) {
24
+ // should not happen, but just in case
25
+ throw new Error('Cannot find block hash');
26
+ }
27
+ return hash;
28
+ });
29
+ }
30
+ else if (typeof options.block === 'string' && options.block.startsWith('0x')) {
31
+ blockHash = options.block;
32
+ }
33
+ else if (Number.isInteger(+options.block)) {
34
+ blockHash = await api.getBlockHash(Number(options.block)).then((hash) => {
35
+ if (!hash) {
36
+ throw new Error(`Cannot find block hash for ${options.block}`);
37
+ }
38
+ return hash;
39
+ });
40
+ }
41
+ else {
42
+ throw new Error(`Invalid block number or hash: ${options.block}`);
43
+ }
44
+ defaultLogger.debug({ ...options, blockHash }, 'Args');
45
+ const header = await api.getHeader(blockHash);
46
+ if (!header) {
47
+ throw new Error(`Cannot find header for ${blockHash}`);
48
+ }
49
+ const inherents = new InherentProviders(new SetTimestamp(), [
50
+ new SetValidationData(),
51
+ new ParaInherentEnter(),
52
+ new SetNimbusAuthorInherent(),
53
+ new SetBabeRandomness(),
54
+ ]);
55
+ return new Blockchain({
56
+ api,
57
+ buildBlockMode: options.buildBlockMode,
58
+ inherentProvider: inherents,
59
+ db: options.db,
60
+ header: {
61
+ hash: blockHash,
62
+ number: Number(header.number),
63
+ },
64
+ mockSignatureHost: options.mockSignatureHost,
65
+ allowUnresolvedImports: options.allowUnresolvedImports,
66
+ runtimeLogLevel: options.runtimeLogLevel,
67
+ registeredTypes: options.registeredTypes || {},
68
+ offchainWorker: options.offchainWorker,
69
+ maxMemoryBlockCount: options.maxMemoryBlockCount,
70
+ });
71
+ };
@@ -0,0 +1,95 @@
1
+ import '@polkadot/types-codec';
2
+ import { blake2AsHex } from '@polkadot/util-crypto';
3
+ import { hexToU8a, u8aToHex } from '@polkadot/util';
4
+ import _ from 'lodash';
5
+ const _CACHE = {};
6
+ const getCache = (uid) => {
7
+ if (!_CACHE[uid]) {
8
+ _CACHE[uid] = new Map();
9
+ }
10
+ return _CACHE[uid];
11
+ };
12
+ const getStorageEntry = (meta, block, key) => {
13
+ const cache = getCache(block.chain.uid);
14
+ for (const [prefix, storageEntry] of cache.entries()) {
15
+ if (key.startsWith(prefix))
16
+ return storageEntry;
17
+ }
18
+ for (const module of Object.values(meta.query)) {
19
+ for (const storage of Object.values(module)) {
20
+ const keyPrefix = u8aToHex(storage.keyPrefix());
21
+ if (key.startsWith(keyPrefix)) {
22
+ cache.set(keyPrefix, storage);
23
+ return storage;
24
+ }
25
+ }
26
+ }
27
+ return undefined;
28
+ };
29
+ export const decodeKey = (meta, block, key) => {
30
+ const storage = getStorageEntry(meta, block, key);
31
+ const decodedKey = meta.registry.createType('StorageKey', key);
32
+ if (storage) {
33
+ decodedKey.setMeta(storage.meta);
34
+ return { storage, decodedKey };
35
+ }
36
+ return {};
37
+ };
38
+ export const decodeKeyValue = (meta, block, key, value, toHuman = true) => {
39
+ const { storage, decodedKey } = decodeKey(meta, block, key);
40
+ if (!storage || !decodedKey) {
41
+ return { [key]: value };
42
+ }
43
+ const decodeValue = () => {
44
+ if (!value)
45
+ return null;
46
+ if (storage.section === 'substrate' && storage.method === 'code') {
47
+ return `:code blake2_256 ${blake2AsHex(value, 256)} (${hexToU8a(value).length} bytes)`;
48
+ }
49
+ return meta.registry.createType(decodedKey.outputType, hexToU8a(value))[toHuman ? 'toHuman' : 'toJSON']();
50
+ };
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
+ };
71
+ }
72
+ default:
73
+ return {
74
+ [storage.section]: {
75
+ [storage.method]: decodeValue(),
76
+ },
77
+ };
78
+ }
79
+ };
80
+ /**
81
+ * Decode block storage diff
82
+ * @param block Block to compare storage diff
83
+ * @param diff Storage diff
84
+ * @returns decoded old state and new state
85
+ */
86
+ export const decodeBlockStorageDiff = async (block, diff) => {
87
+ const oldState = {};
88
+ const newState = {};
89
+ const meta = await block.meta;
90
+ 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));
93
+ }
94
+ return [oldState, newState];
95
+ };
@@ -0,0 +1,91 @@
1
+ import { compactStripLength, u8aToHex } from '@polkadot/util';
2
+ import { hexAddPrefix, hexStripPrefix } from '@polkadot/util/hex';
3
+ export * from './set-storage';
4
+ export * from './time-travel';
5
+ export * from './decoder';
6
+ export async function fetchKeys(getKeys, processKey) {
7
+ const processKeys = async (keys) => {
8
+ for (const key of keys) {
9
+ await processKey(key);
10
+ }
11
+ if (keys.length > 0) {
12
+ return keys[keys.length - 1];
13
+ }
14
+ return undefined;
15
+ };
16
+ const keys = await getKeys();
17
+ let nextKey = await processKeys(keys);
18
+ while (nextKey) {
19
+ const keys = await getKeys(nextKey.toHex());
20
+ nextKey = await processKeys(keys);
21
+ }
22
+ }
23
+ export async function fetchKeysToArray(getKeys) {
24
+ const res = [];
25
+ await fetchKeys(getKeys, (key) => res.push(key));
26
+ return res;
27
+ }
28
+ export const compactHex = (value) => {
29
+ return u8aToHex(compactStripLength(value)[1]);
30
+ };
31
+ export const getParaId = async (chain) => {
32
+ const meta = await chain.head.meta;
33
+ const id = await chain.head.read('u32', meta.query.parachainInfo.parachainId);
34
+ if (!id) {
35
+ throw new Error('Cannot find parachain id');
36
+ }
37
+ return id;
38
+ };
39
+ export const isUrl = (url) => {
40
+ try {
41
+ new URL(url);
42
+ return true;
43
+ }
44
+ catch (e) {
45
+ return false;
46
+ }
47
+ };
48
+ export function defer() {
49
+ const deferred = {};
50
+ deferred.promise = new Promise((resolve, reject) => {
51
+ deferred.resolve = resolve;
52
+ deferred.reject = reject;
53
+ });
54
+ return deferred;
55
+ }
56
+ // Chopsticks treats both main storage and child storage as a key-value store
57
+ // The difference is that child storage keys are prefixed with the child storage key
58
+ // :child_storage:default: as hex string
59
+ const DEFAULT_CHILD_STORAGE = '0x3a6368696c645f73746f726167653a64656661756c743a';
60
+ // length of the child storage key
61
+ const CHILD_LENGTH = DEFAULT_CHILD_STORAGE.length + 64;
62
+ // returns a key that is prefixed with the child storage key
63
+ export const prefixedChildKey = (prefix, key) => prefix + hexStripPrefix(key);
64
+ // returns true if the key is a child storage key
65
+ export const isPrefixedChildKey = (key) => key.startsWith(DEFAULT_CHILD_STORAGE);
66
+ // returns a key that is split into the child storage key and the rest
67
+ export const splitChildKey = (key) => {
68
+ if (!key.startsWith(DEFAULT_CHILD_STORAGE))
69
+ return [];
70
+ if (key.length < CHILD_LENGTH)
71
+ return [];
72
+ const child = key.slice(0, CHILD_LENGTH);
73
+ const rest = key.slice(CHILD_LENGTH);
74
+ return [child, hexAddPrefix(rest)];
75
+ };
76
+ // returns a key that is stripped of the child storage key
77
+ export const stripChildPrefix = (key) => {
78
+ const [child, storageKey] = splitChildKey(key);
79
+ if (!child)
80
+ return key;
81
+ return storageKey;
82
+ };
83
+ export const printRuntimeLogs = (logs) => {
84
+ if (!logs.length)
85
+ return;
86
+ console.group('RuntimeLogs:');
87
+ for (const log of logs) {
88
+ console.log(log);
89
+ }
90
+ console.groupEnd();
91
+ };
@@ -0,0 +1,61 @@
1
+ import _ from 'lodash';
2
+ // 0x + 32 module + 32 method
3
+ export const PREFIX_LENGTH = 66;
4
+ export default class KeyCache {
5
+ constructor() {
6
+ this.ranges = [];
7
+ }
8
+ feed(keys) {
9
+ const _keys = keys.filter((key) => key.length >= PREFIX_LENGTH);
10
+ if (_keys.length === 0)
11
+ return;
12
+ const startKey = _keys[0].slice(PREFIX_LENGTH);
13
+ const endKey = _keys[_keys.length - 1].slice(PREFIX_LENGTH);
14
+ const grouped = _.groupBy(_keys, (key) => key.slice(0, PREFIX_LENGTH));
15
+ for (const [prefix, keys] of Object.entries(grouped)) {
16
+ const ranges = this.ranges.filter((range) => range.prefix === prefix);
17
+ if (ranges.length === 0) {
18
+ // no existing range with prefix
19
+ this.ranges.push({ prefix, keys: keys.map((i) => i.slice(PREFIX_LENGTH)) });
20
+ continue;
21
+ }
22
+ let merged = false;
23
+ for (const range of ranges) {
24
+ const startPosition = _.sortedIndex(range.keys, startKey);
25
+ if (startPosition >= 0 && range.keys[startPosition] === startKey) {
26
+ // found existing range with prefix
27
+ range.keys.splice(startPosition, keys.length, ...keys.map((i) => i.slice(PREFIX_LENGTH)));
28
+ merged = true;
29
+ break;
30
+ }
31
+ const endPosition = _.sortedIndex(range.keys, endKey);
32
+ if (endPosition >= 0 && range.keys[endPosition] === endKey) {
33
+ // found existing range with prefix
34
+ range.keys.splice(0, endPosition + 1, ...keys.map((i) => i.slice(PREFIX_LENGTH)));
35
+ merged = true;
36
+ break;
37
+ }
38
+ }
39
+ // insert new prefix with range
40
+ if (!merged) {
41
+ this.ranges.push({ prefix, keys: keys.map((i) => i.slice(PREFIX_LENGTH)) });
42
+ }
43
+ }
44
+ // TODO: merge ranges if they overlap
45
+ }
46
+ async next(startKey) {
47
+ if (startKey.length < PREFIX_LENGTH)
48
+ return;
49
+ const prefix = startKey.slice(0, PREFIX_LENGTH);
50
+ const key = startKey.slice(PREFIX_LENGTH);
51
+ for (const range of this.ranges.filter((range) => range.prefix === prefix)) {
52
+ const index = _.sortedIndex(range.keys, key);
53
+ if (range.keys[index] !== key)
54
+ continue;
55
+ const nextKey = range.keys[index + 1];
56
+ if (nextKey) {
57
+ return [prefix, nextKey].join('');
58
+ }
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,33 @@
1
+ import { hexToU8a, u8aConcat, u8aToHex } from '@polkadot/util';
2
+ import { xxhashAsU8a } from '@polkadot/util-crypto';
3
+ export const WELL_KNOWN_KEYS = {
4
+ EPOCH_INDEX: '0x1cb6f36e027abb2091cfb5110ab5087f38316cbf8fa0da822a20ac1c55bf1be3',
5
+ CURRENT_BLOCK_RANDOMNESS: '0x1cb6f36e027abb2091cfb5110ab5087fd077dfdb8adb10f78f10a5df8742c545',
6
+ ONE_EPOCH_AGO_RANDOMNESS: '0x1cb6f36e027abb2091cfb5110ab5087f7ce678799d3eff024253b90e84927cc6',
7
+ TWO_EPOCHS_AGO_RANDOMNESS: '0x1cb6f36e027abb2091cfb5110ab5087f7a414cb008e0e61e46722aa60abdd672',
8
+ CURRENT_SLOT: '0x1cb6f36e027abb2091cfb5110ab5087f06155b3cd9a8c9e5e9a23fd5dc13a5ed',
9
+ ACTIVE_CONFIG: '0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385',
10
+ };
11
+ const hash = (prefix, suffix) => {
12
+ return u8aToHex(u8aConcat(hexToU8a(prefix), xxhashAsU8a(suffix, 64), suffix));
13
+ };
14
+ export const dmqMqcHead = (paraId) => {
15
+ const prefix = '0x63f78c98723ddc9073523ef3beefda0c4d7fefc408aac59dbfe80a72ac8e3ce5';
16
+ return hash(prefix, paraId.toU8a());
17
+ };
18
+ export const upgradeGoAheadSignal = (paraId) => {
19
+ const prefix = '0xcd710b30bd2eab0352ddcc26417aa1949e94c040f5e73d9b7addd6cb603d15d3';
20
+ return hash(prefix, paraId.toU8a());
21
+ };
22
+ export const hrmpIngressChannelIndex = (paraId) => {
23
+ const prefix = '0x6a0da05ca59913bc38a8630590f2627c1d3719f5b0b12c7105c073c507445948';
24
+ return hash(prefix, paraId.toU8a());
25
+ };
26
+ export const hrmpEgressChannelIndex = (paraId) => {
27
+ const prefix = '0x6a0da05ca59913bc38a8630590f2627cf12b746dcf32e843354583c9702cc020';
28
+ return hash(prefix, paraId.toU8a());
29
+ };
30
+ export const hrmpChannels = (channelId) => {
31
+ const prefix = '0x6a0da05ca59913bc38a8630590f2627cb6604cff828a6e3f579ca6c59ace013d';
32
+ return hash(prefix, channelId.toU8a());
33
+ };
@@ -0,0 +1,56 @@
1
+ import { StorageKey } from '@polkadot/types';
2
+ import { stringCamelCase } from '@polkadot/util/string';
3
+ import { u8aToHex } from '@polkadot/util';
4
+ import { StorageValueKind } from '../blockchain/storage-layer';
5
+ function objectToStorageItems(meta, storage) {
6
+ const storageItems = [];
7
+ for (const sectionName in storage) {
8
+ const section = storage[sectionName];
9
+ const pallet = meta.query[stringCamelCase(sectionName)];
10
+ if (!pallet)
11
+ throw Error(`Cannot find pallet ${sectionName}`);
12
+ for (const storageName in section) {
13
+ const storage = section[storageName];
14
+ if (storageName === '$removePrefix') {
15
+ for (const mapName of storage) {
16
+ const storageEntry = pallet[stringCamelCase(mapName)];
17
+ if (!storageEntry)
18
+ throw Error(`Cannot find storage ${mapName} in pallet ${sectionName}`);
19
+ const prefix = storageEntry.keyPrefix();
20
+ storageItems.push([u8aToHex(prefix), StorageValueKind.DeletedPrefix]);
21
+ }
22
+ continue;
23
+ }
24
+ const storageEntry = pallet[stringCamelCase(storageName)];
25
+ if (!storageEntry)
26
+ throw Error(`Cannot find storage ${storageName} in pallet ${sectionName}`);
27
+ if (storageEntry.meta.type.isPlain) {
28
+ const key = new StorageKey(meta.registry, [storageEntry]);
29
+ const type = storageEntry.meta.modifier.isOptional ? `Option<${key.outputType}>` : key.outputType;
30
+ storageItems.push([key.toHex(), storage ? meta.registry.createType(type, storage).toHex() : null]);
31
+ }
32
+ else {
33
+ for (const [keys, value] of storage) {
34
+ const key = new StorageKey(meta.registry, [storageEntry, keys]);
35
+ const type = storageEntry.meta.modifier.isOptional ? `Option<${key.outputType}>` : key.outputType;
36
+ storageItems.push([key.toHex(), value ? meta.registry.createType(type, value).toHex() : null]);
37
+ }
38
+ }
39
+ }
40
+ }
41
+ return storageItems;
42
+ }
43
+ export const setStorage = async (chain, storage, blockHash) => {
44
+ const block = await chain.getBlock(blockHash);
45
+ if (!block)
46
+ throw Error(`Cannot find block ${blockHash || 'latest'}`);
47
+ let storageItems;
48
+ if (Array.isArray(storage)) {
49
+ storageItems = storage;
50
+ }
51
+ else {
52
+ storageItems = objectToStorageItems(await block.meta, storage);
53
+ }
54
+ block.pushStorageLayer().setAll(storageItems);
55
+ return block.hash;
56
+ };