@acala-network/chopsticks-core 1.2.5 → 1.2.8

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.
@@ -151,6 +151,7 @@ const newHeader = async (head, unsafeBlockHeight)=>{
151
151
  };
152
152
  const initNewBlock = async (head, header, inherentProviders, params, storageLayer, callback)=>{
153
153
  const blockNumber = header.number.toNumber();
154
+ const { unsafeBlockHeight } = params;
154
155
  const hash = `0x${Math.round(Math.random() * 100000000).toString(16).padEnd(64, '0')}`;
155
156
  const newBlock = new _block.Block(head.chain, blockNumber, hash, head, {
156
157
  header,
@@ -158,6 +159,13 @@ const initNewBlock = async (head, header, inherentProviders, params, storageLaye
158
159
  storage: storageLayer ?? head.storage
159
160
  });
160
161
  {
162
+ // override block number in storage when using unsafeBlockHeight
163
+ // this is needed because the runtime validates that block numbers are strictly increasing
164
+ if (unsafeBlockHeight !== undefined && blockNumber > head.number + 1) {
165
+ const meta = await head.meta;
166
+ const value = meta.registry.createType('BlockNumber', blockNumber - 1).toU8a();
167
+ newBlock.pushStorageLayer().set((0, _index.compactHex)(meta.query.system.number()), (0, _util.u8aToHex)(value));
168
+ }
161
169
  // initialize block
162
170
  const resp = await newBlock.call('Core_initialize_block', [
163
171
  header.toHex()
@@ -196,7 +204,9 @@ const initNewBlock = async (head, header, inherentProviders, params, storageLaye
196
204
  inherents.push(...extrinsics);
197
205
  callback?.onPhaseApplied?.(layers.length - 1, resp);
198
206
  } catch (e) {
199
- logger.warn('Failed to apply inherents %o %s', e, e);
207
+ logger.warn({
208
+ err: e
209
+ }, 'Failed to apply inherents');
200
210
  throw new Error('Failed to apply inherents');
201
211
  }
202
212
  }
@@ -322,7 +332,9 @@ const buildBlock = async (head, inherentProviders, params, callbacks)=>{
322
332
  includedExtrinsic.push(extrinsic);
323
333
  callbacks?.onPhaseApplied?.(includedExtrinsic.length - 1, resp);
324
334
  } catch (e) {
325
- logger.info('Failed to apply extrinsic %o %s', e, e);
335
+ logger.info({
336
+ err: e
337
+ }, 'Failed to apply extrinsic');
326
338
  pendingExtrinsics.push(extrinsic);
327
339
  }
328
340
  }
@@ -3,8 +3,8 @@ import type { Block } from '../../block.js';
3
3
  import type { BuildBlockParams, DownwardMessage, HorizontalMessage } from '../../txpool.js';
4
4
  import type { InherentProvider } from '../index.js';
5
5
  export type ValidationData = {
6
- downwardMessages: DownwardMessage[];
7
- horizontalMessages: Record<number, HorizontalMessage[]>;
6
+ downwardMessages?: DownwardMessage[];
7
+ horizontalMessages?: Record<number, HorizontalMessage[]>;
8
8
  validationData: {
9
9
  relayParentNumber: number;
10
10
  relayParentStorageRoot: HexString;
@@ -51,8 +51,7 @@ const MOCK_VALIDATION_DATA = {
51
51
  horizontalMessages: [],
52
52
  downwardMessages: []
53
53
  };
54
- const getValidationData = async (parent, fallback = true)=>{
55
- const meta = await parent.meta;
54
+ const getValidationData = async (parent)=>{
56
55
  if (parent.number === 0) {
57
56
  const { trieRootHash, nodes } = await (0, _index1.createProof)(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
58
57
  return {
@@ -66,39 +65,19 @@ const getValidationData = async (parent, fallback = true)=>{
66
65
  }
67
66
  };
68
67
  }
69
- try {
70
- const extrinsics = await parent.extrinsics;
71
- const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
72
- const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
73
- return firstArg && 'validationData' in firstArg;
74
- });
75
- if (!validationDataExtrinsic) {
76
- throw new Error('Missing validation data from block');
77
- }
78
- return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
79
- } catch (e) {
80
- logger.warn('Failed to get validation data from block %d %s', parent.number, e);
81
- if (fallback) {
82
- // this could fail due to wasm override that breaks the validation data format
83
- // so we will try parent's parent
84
- const grandParent = await parent.parentBlock;
85
- if (grandParent) {
86
- const data = await getValidationData(grandParent, false);
87
- return {
88
- ...data,
89
- validationData: {
90
- ...data.validationData,
91
- relayParentNumber: data.validationData.relayParentNumber + 2
92
- }
93
- };
94
- } else {
95
- throw e;
96
- }
97
- } else {
98
- // fallback failed, throw error
99
- throw e;
100
- }
68
+ // Parent extrinsics are encoded by grand parent meta and new block extrinsics are encoded with parent meta.
69
+ const grandParent = await parent.parentBlock;
70
+ if (!grandParent) throw new Error('grand parent block not found');
71
+ const grandMeta = await grandParent.meta;
72
+ const extrinsics = await parent.extrinsics;
73
+ const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
74
+ const firstArg = grandMeta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
75
+ return firstArg && 'validationData' in firstArg;
76
+ });
77
+ if (!validationDataExtrinsic) {
78
+ throw new Error('Missing validation data from block');
101
79
  }
80
+ return grandMeta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
102
81
  };
103
82
  class SetValidationData {
104
83
  async createInherents(newBlock, params) {
@@ -144,7 +144,9 @@ class RemoteStorageLayer {
144
144
  blockHash: _class_private_field_get(this, _at)
145
145
  })));
146
146
  } else if (_class_private_field_get(this, _db)) {
147
- data.forEach(([key, value])=>_class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, value));
147
+ data.forEach(([key, value])=>{
148
+ _class_private_field_get(this, _db)?.saveStorage(_class_private_field_get(this, _at), key, value);
149
+ });
148
150
  }
149
151
  }
150
152
  return result;
@@ -156,7 +156,11 @@ class ChopsticksProvider {
156
156
  sub.onCancel = onCancel;
157
157
  }
158
158
  return (data)=>{
159
- logger.debug('subscribe-callback', method, subid, data);
159
+ logger.debug({
160
+ method,
161
+ subid,
162
+ data
163
+ }, 'subscribe-callback');
160
164
  const sub = _class_private_field_get(this, _subscriptions)[subid];
161
165
  if (sub) {
162
166
  sub.callback(null, data);
@@ -166,7 +170,9 @@ class ChopsticksProvider {
166
170
  };
167
171
  },
168
172
  unsubscribe: (subid)=>{
169
- logger.debug('unsubscribe-callback', subid);
173
+ logger.debug({
174
+ subid
175
+ }, 'unsubscribe-callback');
170
176
  const sub = _class_private_field_get(this, _subscriptions)[subid];
171
177
  if (sub) {
172
178
  sub.onCancel?.();
@@ -178,20 +184,20 @@ class ChopsticksProvider {
178
184
  };
179
185
  this.send = async (method, params, _isCacheable, subscription)=>{
180
186
  try {
181
- logger.debug('send', {
187
+ logger.debug({
182
188
  method,
183
189
  params
184
- });
190
+ }, 'send');
185
191
  const rpcHandler = providerHandlers[method];
186
192
  if (!rpcHandler) {
187
193
  logger.error(`Unable to find rpc handler=${method}`);
188
194
  throw new Error(`Unable to find rpc handler=${method}`);
189
195
  }
190
196
  if (subscription) {
191
- logger.debug('subscribe', {
197
+ logger.debug({
192
198
  method,
193
199
  params
194
- });
200
+ }, 'subscribe');
195
201
  const subid = await rpcHandler({
196
202
  chain: this.chain
197
203
  }, params, this.subscriptionManager);
@@ -206,15 +212,17 @@ class ChopsticksProvider {
206
212
  };
207
213
  return subid;
208
214
  }
209
- logger.debug('call', {
215
+ logger.debug({
210
216
  method,
211
217
  params
212
- });
218
+ }, 'call');
213
219
  return rpcHandler({
214
220
  chain: this.chain
215
221
  }, params, this.subscriptionManager);
216
222
  } catch (e) {
217
- logger.error('send error.', e);
223
+ logger.error({
224
+ err: e
225
+ }, 'send error');
218
226
  throw e;
219
227
  }
220
228
  };
@@ -1,4 +1,3 @@
1
- import { pino } from 'pino';
2
1
  export declare const pinoLogger: import("pino").Logger<never, boolean>;
3
- export declare const defaultLogger: pino.Logger<never, boolean>;
2
+ export declare const defaultLogger: import("pino").Logger<never, boolean>;
4
3
  export declare const truncate: (val: any) => any;
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import type { Blockchain } from '../blockchain/index.js';
3
- export declare const logger: import("pino").default.Logger<never, boolean>;
3
+ export declare const logger: import("pino").Logger<never, boolean>;
4
4
  export declare const zHex: z.ZodType<`0x${string}`, z.ZodTypeDef, `0x${string}`>;
5
5
  export declare const zHash: z.ZodIntersection<z.ZodString, z.ZodType<`0x${string}`, z.ZodTypeDef, `0x${string}`>>;
6
6
  export declare class ResponseError extends Error {
package/dist/cjs/setup.js CHANGED
@@ -26,10 +26,13 @@ const processOptions = async (options)=>{
26
26
  _logger.defaultLogger.debug(options, 'Setup options');
27
27
  let provider;
28
28
  if (options.genesis) {
29
+ _logger.defaultLogger.debug(options, 'Setup options - genesis');
29
30
  provider = options.genesis;
30
31
  } else if (typeof options.endpoint === 'string' && /^(https|http):\/\//.test(options.endpoint || '')) {
32
+ _logger.defaultLogger.debug(options, 'Setup options - HTTP');
31
33
  provider = new _rpcprovider.HttpProvider(options.endpoint);
32
34
  } else {
35
+ _logger.defaultLogger.debug(options, 'Setup options - WS');
33
36
  provider = new _rpcprovider.WsProvider(options.endpoint, 3_000, undefined, options.rpcTimeout);
34
37
  }
35
38
  const api = new _api.Api(provider);
@@ -1,4 +1,4 @@
1
1
  import type { Blockchain } from '../blockchain/index.js';
2
- export declare const xcmLogger: import("pino").default.Logger<never, boolean>;
2
+ export declare const xcmLogger: import("pino").Logger<never, boolean>;
3
3
  export declare const connectVertical: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
4
4
  export declare const connectParachains: (parachains: Blockchain[], disableAutoHrmp?: boolean) => Promise<void>;
@@ -1,4 +1,4 @@
1
- import { compactAddLength, hexToU8a, stringToHex, u8aConcat } from '@polkadot/util';
1
+ import { compactAddLength, hexToU8a, stringToHex, u8aConcat, u8aToHex } from '@polkadot/util';
2
2
  import { blake2AsU8a } from '@polkadot/util-crypto';
3
3
  import { defaultLogger, truncate } from '../logger.js';
4
4
  import { compactHex, getCurrentSlot } from '../utils/index.js';
@@ -127,6 +127,7 @@ export const newHeader = async (head, unsafeBlockHeight)=>{
127
127
  };
128
128
  const initNewBlock = async (head, header, inherentProviders, params, storageLayer, callback)=>{
129
129
  const blockNumber = header.number.toNumber();
130
+ const { unsafeBlockHeight } = params;
130
131
  const hash = `0x${Math.round(Math.random() * 100000000).toString(16).padEnd(64, '0')}`;
131
132
  const newBlock = new Block(head.chain, blockNumber, hash, head, {
132
133
  header,
@@ -134,6 +135,13 @@ const initNewBlock = async (head, header, inherentProviders, params, storageLaye
134
135
  storage: storageLayer ?? head.storage
135
136
  });
136
137
  {
138
+ // override block number in storage when using unsafeBlockHeight
139
+ // this is needed because the runtime validates that block numbers are strictly increasing
140
+ if (unsafeBlockHeight !== undefined && blockNumber > head.number + 1) {
141
+ const meta = await head.meta;
142
+ const value = meta.registry.createType('BlockNumber', blockNumber - 1).toU8a();
143
+ newBlock.pushStorageLayer().set(compactHex(meta.query.system.number()), u8aToHex(value));
144
+ }
137
145
  // initialize block
138
146
  const resp = await newBlock.call('Core_initialize_block', [
139
147
  header.toHex()
@@ -172,7 +180,9 @@ const initNewBlock = async (head, header, inherentProviders, params, storageLaye
172
180
  inherents.push(...extrinsics);
173
181
  callback?.onPhaseApplied?.(layers.length - 1, resp);
174
182
  } catch (e) {
175
- logger.warn('Failed to apply inherents %o %s', e, e);
183
+ logger.warn({
184
+ err: e
185
+ }, 'Failed to apply inherents');
176
186
  throw new Error('Failed to apply inherents');
177
187
  }
178
188
  }
@@ -298,7 +308,9 @@ export const buildBlock = async (head, inherentProviders, params, callbacks)=>{
298
308
  includedExtrinsic.push(extrinsic);
299
309
  callbacks?.onPhaseApplied?.(includedExtrinsic.length - 1, resp);
300
310
  } catch (e) {
301
- logger.info('Failed to apply extrinsic %o %s', e, e);
311
+ logger.info({
312
+ err: e
313
+ }, 'Failed to apply extrinsic');
302
314
  pendingExtrinsics.push(extrinsic);
303
315
  }
304
316
  }
@@ -3,8 +3,8 @@ import type { Block } from '../../block.js';
3
3
  import type { BuildBlockParams, DownwardMessage, HorizontalMessage } from '../../txpool.js';
4
4
  import type { InherentProvider } from '../index.js';
5
5
  export type ValidationData = {
6
- downwardMessages: DownwardMessage[];
7
- horizontalMessages: Record<number, HorizontalMessage[]>;
6
+ downwardMessages?: DownwardMessage[];
7
+ horizontalMessages?: Record<number, HorizontalMessage[]>;
8
8
  validationData: {
9
9
  relayParentNumber: number;
10
10
  relayParentStorageRoot: HexString;
@@ -36,8 +36,7 @@ const MOCK_VALIDATION_DATA = {
36
36
  horizontalMessages: [],
37
37
  downwardMessages: []
38
38
  };
39
- const getValidationData = async (parent, fallback = true)=>{
40
- const meta = await parent.meta;
39
+ const getValidationData = async (parent)=>{
41
40
  if (parent.number === 0) {
42
41
  const { trieRootHash, nodes } = await createProof(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
43
42
  return {
@@ -51,39 +50,19 @@ const getValidationData = async (parent, fallback = true)=>{
51
50
  }
52
51
  };
53
52
  }
54
- try {
55
- const extrinsics = await parent.extrinsics;
56
- const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
57
- const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
58
- return firstArg && 'validationData' in firstArg;
59
- });
60
- if (!validationDataExtrinsic) {
61
- throw new Error('Missing validation data from block');
62
- }
63
- return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
64
- } catch (e) {
65
- logger.warn('Failed to get validation data from block %d %s', parent.number, e);
66
- if (fallback) {
67
- // this could fail due to wasm override that breaks the validation data format
68
- // so we will try parent's parent
69
- const grandParent = await parent.parentBlock;
70
- if (grandParent) {
71
- const data = await getValidationData(grandParent, false);
72
- return {
73
- ...data,
74
- validationData: {
75
- ...data.validationData,
76
- relayParentNumber: data.validationData.relayParentNumber + 2
77
- }
78
- };
79
- } else {
80
- throw e;
81
- }
82
- } else {
83
- // fallback failed, throw error
84
- throw e;
85
- }
53
+ // Parent extrinsics are encoded by grand parent meta and new block extrinsics are encoded with parent meta.
54
+ const grandParent = await parent.parentBlock;
55
+ if (!grandParent) throw new Error('grand parent block not found');
56
+ const grandMeta = await grandParent.meta;
57
+ const extrinsics = await parent.extrinsics;
58
+ const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
59
+ const firstArg = grandMeta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
60
+ return firstArg && 'validationData' in firstArg;
61
+ });
62
+ if (!validationDataExtrinsic) {
63
+ throw new Error('Missing validation data from block');
86
64
  }
65
+ return grandMeta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
87
66
  };
88
67
  export class SetValidationData {
89
68
  async createInherents(newBlock, params) {
@@ -77,7 +77,9 @@ export class RemoteStorageLayer {
77
77
  blockHash: this.#at
78
78
  })));
79
79
  } else if (this.#db) {
80
- data.forEach(([key, value])=>this.#db?.saveStorage(this.#at, key, value));
80
+ data.forEach(([key, value])=>{
81
+ this.#db?.saveStorage(this.#at, key, value);
82
+ });
81
83
  }
82
84
  }
83
85
  return result;
@@ -68,7 +68,11 @@ const logger = defaultLogger.child({
68
68
  sub.onCancel = onCancel;
69
69
  }
70
70
  return (data)=>{
71
- logger.debug('subscribe-callback', method, subid, data);
71
+ logger.debug({
72
+ method,
73
+ subid,
74
+ data
75
+ }, 'subscribe-callback');
72
76
  const sub = this.#subscriptions[subid];
73
77
  if (sub) {
74
78
  sub.callback(null, data);
@@ -78,7 +82,9 @@ const logger = defaultLogger.child({
78
82
  };
79
83
  },
80
84
  unsubscribe: (subid)=>{
81
- logger.debug('unsubscribe-callback', subid);
85
+ logger.debug({
86
+ subid
87
+ }, 'unsubscribe-callback');
82
88
  const sub = this.#subscriptions[subid];
83
89
  if (sub) {
84
90
  sub.onCancel?.();
@@ -90,20 +96,20 @@ const logger = defaultLogger.child({
90
96
  };
91
97
  send = async (method, params, _isCacheable, subscription)=>{
92
98
  try {
93
- logger.debug('send', {
99
+ logger.debug({
94
100
  method,
95
101
  params
96
- });
102
+ }, 'send');
97
103
  const rpcHandler = providerHandlers[method];
98
104
  if (!rpcHandler) {
99
105
  logger.error(`Unable to find rpc handler=${method}`);
100
106
  throw new Error(`Unable to find rpc handler=${method}`);
101
107
  }
102
108
  if (subscription) {
103
- logger.debug('subscribe', {
109
+ logger.debug({
104
110
  method,
105
111
  params
106
- });
112
+ }, 'subscribe');
107
113
  const subid = await rpcHandler({
108
114
  chain: this.chain
109
115
  }, params, this.subscriptionManager);
@@ -118,15 +124,17 @@ const logger = defaultLogger.child({
118
124
  };
119
125
  return subid;
120
126
  }
121
- logger.debug('call', {
127
+ logger.debug({
122
128
  method,
123
129
  params
124
- });
130
+ }, 'call');
125
131
  return rpcHandler({
126
132
  chain: this.chain
127
133
  }, params, this.subscriptionManager);
128
134
  } catch (e) {
129
- logger.error('send error.', e);
135
+ logger.error({
136
+ err: e
137
+ }, 'send error');
130
138
  throw e;
131
139
  }
132
140
  };
@@ -1,4 +1,3 @@
1
- import { pino } from 'pino';
2
1
  export declare const pinoLogger: import("pino").Logger<never, boolean>;
3
- export declare const defaultLogger: pino.Logger<never, boolean>;
2
+ export declare const defaultLogger: import("pino").Logger<never, boolean>;
4
3
  export declare const truncate: (val: any) => any;
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import type { Blockchain } from '../blockchain/index.js';
3
- export declare const logger: import("pino").default.Logger<never, boolean>;
3
+ export declare const logger: import("pino").Logger<never, boolean>;
4
4
  export declare const zHex: z.ZodType<`0x${string}`, z.ZodTypeDef, `0x${string}`>;
5
5
  export declare const zHash: z.ZodIntersection<z.ZodString, z.ZodType<`0x${string}`, z.ZodTypeDef, `0x${string}`>>;
6
6
  export declare class ResponseError extends Error {
package/dist/esm/setup.js CHANGED
@@ -8,10 +8,13 @@ export const processOptions = async (options)=>{
8
8
  defaultLogger.debug(options, 'Setup options');
9
9
  let provider;
10
10
  if (options.genesis) {
11
+ defaultLogger.debug(options, 'Setup options - genesis');
11
12
  provider = options.genesis;
12
13
  } else if (typeof options.endpoint === 'string' && /^(https|http):\/\//.test(options.endpoint || '')) {
14
+ defaultLogger.debug(options, 'Setup options - HTTP');
13
15
  provider = new HttpProvider(options.endpoint);
14
16
  } else {
17
+ defaultLogger.debug(options, 'Setup options - WS');
15
18
  provider = new WsProvider(options.endpoint, 3_000, undefined, options.rpcTimeout);
16
19
  }
17
20
  const api = new Api(provider);
@@ -1,4 +1,4 @@
1
1
  import type { Blockchain } from '../blockchain/index.js';
2
- export declare const xcmLogger: import("pino").default.Logger<never, boolean>;
2
+ export declare const xcmLogger: import("pino").Logger<never, boolean>;
3
3
  export declare const connectVertical: (relaychain: Blockchain, parachain: Blockchain) => Promise<void>;
4
4
  export declare const connectParachains: (parachains: Blockchain[], disableAutoHrmp?: boolean) => Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks-core",
3
- "version": "1.2.5",
3
+ "version": "1.2.8",
4
4
  "author": "Acala Developers <hello@acala.network>",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -14,13 +14,13 @@
14
14
  "depcheck": "npx depcheck"
15
15
  },
16
16
  "dependencies": {
17
- "@acala-network/chopsticks-executor": "1.2.5",
17
+ "@acala-network/chopsticks-executor": "1.2.8",
18
18
  "@polkadot/rpc-provider": "^16.4.1",
19
19
  "@polkadot/types": "^16.4.1",
20
20
  "@polkadot/types-codec": "^16.4.1",
21
21
  "@polkadot/types-known": "^16.4.1",
22
- "@polkadot/util": "^13.5.3",
23
- "@polkadot/util-crypto": "^13.5.3",
22
+ "@polkadot/util": "^14.0.1",
23
+ "@polkadot/util-crypto": "^14.0.1",
24
24
  "comlink": "^4.4.2",
25
25
  "eventemitter3": "^5.0.1",
26
26
  "lodash": "^4.17.21",
@@ -31,11 +31,11 @@
31
31
  "zod": "^3.25.76"
32
32
  },
33
33
  "devDependencies": {
34
- "@swc/cli": "0.7.8",
34
+ "@swc/cli": "0.7.10",
35
35
  "@swc/core": "^1.12.14",
36
36
  "@types/lodash": "^4.17.20",
37
37
  "typescript": "^5.8.3",
38
- "vitest": "^3.2.4"
38
+ "vitest": "^4.0.18"
39
39
  },
40
40
  "files": [
41
41
  "dist/esm/**",