@acala-network/chopsticks-core 0.9.10 → 0.9.11-1

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.
@@ -37,6 +37,8 @@ export interface Options {
37
37
  offchainWorker?: boolean;
38
38
  /** Max memory block count */
39
39
  maxMemoryBlockCount?: number;
40
+ /** Whether to process queued messages */
41
+ processQueuedMessages?: boolean;
40
42
  }
41
43
  /**
42
44
  * Local blockchain which provides access to blocks, txpool and methods
@@ -76,10 +78,11 @@ export declare class Blockchain {
76
78
  /** For subscribing and managing the head state. */
77
79
  readonly headState: HeadState;
78
80
  readonly offchainWorker: OffchainWorker | undefined;
81
+ readonly processQueuedMessages: boolean;
79
82
  /**
80
83
  * @param options - Options for instantiating the blockchain
81
84
  */
82
- constructor({ api, buildBlockMode, inherentProviders, db, header, mockSignatureHost, allowUnresolvedImports, runtimeLogLevel, registeredTypes, offchainWorker, maxMemoryBlockCount, }: Options);
85
+ constructor({ api, buildBlockMode, inherentProviders, db, header, mockSignatureHost, allowUnresolvedImports, runtimeLogLevel, registeredTypes, offchainWorker, maxMemoryBlockCount, processQueuedMessages, }: Options);
83
86
  get head(): Block;
84
87
  get txPool(): TxPool;
85
88
  get runtimeLogLevel(): number;
@@ -414,7 +414,7 @@ class Blockchain {
414
414
  }
415
415
  /**
416
416
  * @param options - Options for instantiating the blockchain
417
- */ constructor({ api, buildBlockMode, inherentProviders, db, header, mockSignatureHost = false, allowUnresolvedImports = false, runtimeLogLevel = 0, registeredTypes = {}, offchainWorker = false, maxMemoryBlockCount = 500 }){
417
+ */ constructor({ api, buildBlockMode, inherentProviders, db, header, mockSignatureHost = false, allowUnresolvedImports = false, runtimeLogLevel = 0, registeredTypes = {}, offchainWorker = false, maxMemoryBlockCount = 500, processQueuedMessages = true }){
418
418
  _class_private_method_init(this, _registerBlock);
419
419
  /** API instance, for getting on-chain data. */ _define_property(this, "api", void 0);
420
420
  /** Datasource for caching storage and blocks data. */ _define_property(this, "db", void 0);
@@ -455,6 +455,7 @@ class Blockchain {
455
455
  writable: true,
456
456
  value: void 0
457
457
  });
458
+ _define_property(this, "processQueuedMessages", true);
458
459
  // first arg is used as cache key
459
460
  _class_private_field_init(this, _registryBuilder, {
460
461
  writable: true,
@@ -485,6 +486,7 @@ class Blockchain {
485
486
  this.offchainWorker = new _offchain.OffchainWorker();
486
487
  }
487
488
  _class_private_field_set(this, _maxMemoryBlockCount, maxMemoryBlockCount);
489
+ this.processQueuedMessages = processQueuedMessages;
488
490
  }
489
491
  }
490
492
  function registerBlock(block) {
@@ -290,8 +290,8 @@ class StorageLayer {
290
290
  };
291
291
  const res = [];
292
292
  const foundNextKey = (key)=>{
293
- // make sure keys are unique
294
- if (!res.includes(key)) {
293
+ // make sure keys are unique and start with the prefix
294
+ if (!res.includes(key) && key.startsWith(prefix)) {
295
295
  res.push(key);
296
296
  }
297
297
  };
@@ -311,7 +311,7 @@ class StorageLayer {
311
311
  if (idx !== -1) {
312
312
  if (includeFirst) {
313
313
  const key = _class_private_field_get(this, _keys)[idx];
314
- if (key) {
314
+ if (key && key.startsWith(prefix)) {
315
315
  foundNextKey(key);
316
316
  }
317
317
  }
@@ -20,6 +20,7 @@ _export(exports, {
20
20
  }
21
21
  });
22
22
  const _eventemitter3 = require("eventemitter3");
23
+ const _toU8a = require("@polkadot/util/hex/toU8a");
23
24
  const _lodash = /*#__PURE__*/ _interop_require_default(require("lodash"));
24
25
  const _index = require("../utils/index.js");
25
26
  const _blockbuilder = require("./block-builder.js");
@@ -210,6 +211,27 @@ class TxPool {
210
211
  horizontalMessages,
211
212
  unsafeBlockHeight
212
213
  });
214
+ // with the latest message queue, messages are processed in the upcoming block
215
+ if (!_class_private_field_get(this, _chain).processQueuedMessages || !params?.horizontalMessages) return;
216
+ if (!(params?.horizontalMessages || params?.downwardMessages)) return;
217
+ // messageQueue.bookStateFor
218
+ const prefix = '0xb8753e9383841da95f7b8871e5de326954e062a2cf8df68178ee2e5dbdf00bff';
219
+ const meta = await _class_private_field_get(this, _chain).head.meta;
220
+ const keys = await _class_private_field_get(this, _chain).head.getKeysPaged({
221
+ prefix,
222
+ pageSize: 1000
223
+ });
224
+ for (const key of keys){
225
+ const rawValue = await _class_private_field_get(this, _chain).head.get(key);
226
+ if (!rawValue) continue;
227
+ const message = meta.registry.createType('PalletMessageQueueBookState', (0, _toU8a.hexToU8a)(rawValue)).toJSON();
228
+ if (message.size > 0) {
229
+ logger.info('Queued messages detected, building a new block');
230
+ // build a new block to process the queued messages
231
+ await _class_private_field_get(this, _chain).newBlock();
232
+ return;
233
+ }
234
+ }
213
235
  } catch (err) {
214
236
  logger.error({
215
237
  err
@@ -17,6 +17,7 @@ export type SetupOptions = {
17
17
  registeredTypes?: RegisteredTypes;
18
18
  offchainWorker?: boolean;
19
19
  maxMemoryBlockCount?: number;
20
+ processQueuedMessages?: boolean;
20
21
  };
21
22
  export declare const genesisSetup: (chain: Blockchain, genesis: GenesisProvider) => Promise<void>;
22
23
  export declare const processOptions: (options: SetupOptions) => Promise<{
@@ -33,5 +34,6 @@ export declare const processOptions: (options: SetupOptions) => Promise<{
33
34
  registeredTypes?: RegisteredTypes | undefined;
34
35
  offchainWorker?: boolean | undefined;
35
36
  maxMemoryBlockCount?: number | undefined;
37
+ processQueuedMessages?: boolean | undefined;
36
38
  }>;
37
39
  export declare const setup: (options: SetupOptions) => Promise<Blockchain>;
package/dist/cjs/setup.js CHANGED
@@ -129,7 +129,8 @@ const setup = async (options)=>{
129
129
  runtimeLogLevel: opts.runtimeLogLevel,
130
130
  registeredTypes: opts.registeredTypes || {},
131
131
  offchainWorker: opts.offchainWorker,
132
- maxMemoryBlockCount: opts.maxMemoryBlockCount
132
+ maxMemoryBlockCount: opts.maxMemoryBlockCount,
133
+ processQueuedMessages: opts.processQueuedMessages
133
134
  });
134
135
  if (opts.genesis) {
135
136
  await genesisSetup(chain, opts.genesis);
@@ -170,5 +170,5 @@ const getCurrentTimestamp = async (chain)=>{
170
170
  };
171
171
  const getSlotDuration = async (chain)=>{
172
172
  const meta = await chain.head.meta;
173
- return meta.consts.babe ? meta.consts.babe.expectedBlockTime.toNumber() : meta.query.aura ? (0, _index.getAuraSlotDuration)(await chain.head.wasm) : 12_000;
173
+ return meta.consts.babe ? meta.consts.babe.expectedBlockTime.toNumber() : meta.query.aura ? (0, _index.getAuraSlotDuration)(await chain.head.wasm) : meta.consts.asyncBacking ? meta.consts.asyncBacking.expectedBlockTime.toNumber() : 12_000;
174
174
  };
@@ -37,5 +37,14 @@ const connectHorizontal = async (parachains)=>{
37
37
  }
38
38
  }
39
39
  });
40
+ const hrmpHeads = await chain.head.read('BTreeMap<u32, H256>', meta.query.parachainSystem.lastHrmpMqcHeads);
41
+ if (hrmpHeads && !process.env.DISABLE_AUTO_HRMP) {
42
+ const existingChannels = Array.from(hrmpHeads.keys()).map((x)=>x.toNumber());
43
+ for (const paraId of Object.keys(parachains).filter((x)=>x !== id)){
44
+ if (!existingChannels.includes(Number(paraId))) {
45
+ chain.submitHorizontalMessages(Number(paraId), []);
46
+ }
47
+ }
48
+ }
40
49
  }
41
50
  };
@@ -37,6 +37,8 @@ export interface Options {
37
37
  offchainWorker?: boolean;
38
38
  /** Max memory block count */
39
39
  maxMemoryBlockCount?: number;
40
+ /** Whether to process queued messages */
41
+ processQueuedMessages?: boolean;
40
42
  }
41
43
  /**
42
44
  * Local blockchain which provides access to blocks, txpool and methods
@@ -76,10 +78,11 @@ export declare class Blockchain {
76
78
  /** For subscribing and managing the head state. */
77
79
  readonly headState: HeadState;
78
80
  readonly offchainWorker: OffchainWorker | undefined;
81
+ readonly processQueuedMessages: boolean;
79
82
  /**
80
83
  * @param options - Options for instantiating the blockchain
81
84
  */
82
- constructor({ api, buildBlockMode, inherentProviders, db, header, mockSignatureHost, allowUnresolvedImports, runtimeLogLevel, registeredTypes, offchainWorker, maxMemoryBlockCount, }: Options);
85
+ constructor({ api, buildBlockMode, inherentProviders, db, header, mockSignatureHost, allowUnresolvedImports, runtimeLogLevel, registeredTypes, offchainWorker, maxMemoryBlockCount, processQueuedMessages, }: Options);
83
86
  get head(): Block;
84
87
  get txPool(): TxPool;
85
88
  get runtimeLogLevel(): number;
@@ -51,6 +51,7 @@ const logger = defaultLogger.child({
51
51
  /** For subscribing and managing the head state. */ headState;
52
52
  offchainWorker;
53
53
  #maxMemoryBlockCount;
54
+ processQueuedMessages = true;
54
55
  // first arg is used as cache key
55
56
  #registryBuilder = _.memoize(async (_cacheKey, metadata, version)=>{
56
57
  const chain = await this.api.chain;
@@ -65,7 +66,7 @@ const logger = defaultLogger.child({
65
66
  });
66
67
  /**
67
68
  * @param options - Options for instantiating the blockchain
68
- */ constructor({ api, buildBlockMode, inherentProviders, db, header, mockSignatureHost = false, allowUnresolvedImports = false, runtimeLogLevel = 0, registeredTypes = {}, offchainWorker = false, maxMemoryBlockCount = 500 }){
69
+ */ constructor({ api, buildBlockMode, inherentProviders, db, header, mockSignatureHost = false, allowUnresolvedImports = false, runtimeLogLevel = 0, registeredTypes = {}, offchainWorker = false, maxMemoryBlockCount = 500, processQueuedMessages = true }){
69
70
  this.api = api;
70
71
  this.db = db;
71
72
  this.mockSignatureHost = mockSignatureHost;
@@ -81,6 +82,7 @@ const logger = defaultLogger.child({
81
82
  this.offchainWorker = new OffchainWorker();
82
83
  }
83
84
  this.#maxMemoryBlockCount = maxMemoryBlockCount;
85
+ this.processQueuedMessages = processQueuedMessages;
84
86
  }
85
87
  #registerBlock(block) {
86
88
  // if exceed max memory block count, delete the oldest block
@@ -219,8 +219,8 @@ export class StorageLayer {
219
219
  };
220
220
  const res = [];
221
221
  const foundNextKey = (key)=>{
222
- // make sure keys are unique
223
- if (!res.includes(key)) {
222
+ // make sure keys are unique and start with the prefix
223
+ if (!res.includes(key) && key.startsWith(prefix)) {
224
224
  res.push(key);
225
225
  }
226
226
  };
@@ -240,7 +240,7 @@ export class StorageLayer {
240
240
  if (idx !== -1) {
241
241
  if (includeFirst) {
242
242
  const key = this.#keys[idx];
243
- if (key) {
243
+ if (key && key.startsWith(prefix)) {
244
244
  foundNextKey(key);
245
245
  }
246
246
  }
@@ -1,4 +1,5 @@
1
1
  import { EventEmitter } from 'eventemitter3';
2
+ import { hexToU8a } from '@polkadot/util/hex/toU8a';
2
3
  import _ from 'lodash';
3
4
  import { defer } from '../utils/index.js';
4
5
  import { buildBlock } from './block-builder.js';
@@ -155,6 +156,27 @@ export class TxPool {
155
156
  horizontalMessages,
156
157
  unsafeBlockHeight
157
158
  });
159
+ // with the latest message queue, messages are processed in the upcoming block
160
+ if (!this.#chain.processQueuedMessages || !params?.horizontalMessages) return;
161
+ if (!(params?.horizontalMessages || params?.downwardMessages)) return;
162
+ // messageQueue.bookStateFor
163
+ const prefix = '0xb8753e9383841da95f7b8871e5de326954e062a2cf8df68178ee2e5dbdf00bff';
164
+ const meta = await this.#chain.head.meta;
165
+ const keys = await this.#chain.head.getKeysPaged({
166
+ prefix,
167
+ pageSize: 1000
168
+ });
169
+ for (const key of keys){
170
+ const rawValue = await this.#chain.head.get(key);
171
+ if (!rawValue) continue;
172
+ const message = meta.registry.createType('PalletMessageQueueBookState', hexToU8a(rawValue)).toJSON();
173
+ if (message.size > 0) {
174
+ logger.info('Queued messages detected, building a new block');
175
+ // build a new block to process the queued messages
176
+ await this.#chain.newBlock();
177
+ return;
178
+ }
179
+ }
158
180
  } catch (err) {
159
181
  logger.error({
160
182
  err
@@ -17,6 +17,7 @@ export type SetupOptions = {
17
17
  registeredTypes?: RegisteredTypes;
18
18
  offchainWorker?: boolean;
19
19
  maxMemoryBlockCount?: number;
20
+ processQueuedMessages?: boolean;
20
21
  };
21
22
  export declare const genesisSetup: (chain: Blockchain, genesis: GenesisProvider) => Promise<void>;
22
23
  export declare const processOptions: (options: SetupOptions) => Promise<{
@@ -33,5 +34,6 @@ export declare const processOptions: (options: SetupOptions) => Promise<{
33
34
  registeredTypes?: RegisteredTypes | undefined;
34
35
  offchainWorker?: boolean | undefined;
35
36
  maxMemoryBlockCount?: number | undefined;
37
+ processQueuedMessages?: boolean | undefined;
36
38
  }>;
37
39
  export declare const setup: (options: SetupOptions) => Promise<Blockchain>;
package/dist/esm/setup.js CHANGED
@@ -108,7 +108,8 @@ export const setup = async (options)=>{
108
108
  runtimeLogLevel: opts.runtimeLogLevel,
109
109
  registeredTypes: opts.registeredTypes || {},
110
110
  offchainWorker: opts.offchainWorker,
111
- maxMemoryBlockCount: opts.maxMemoryBlockCount
111
+ maxMemoryBlockCount: opts.maxMemoryBlockCount,
112
+ processQueuedMessages: opts.processQueuedMessages
112
113
  });
113
114
  if (opts.genesis) {
114
115
  await genesisSetup(chain, opts.genesis);
@@ -106,5 +106,5 @@ export const getCurrentTimestamp = async (chain)=>{
106
106
  };
107
107
  export const getSlotDuration = async (chain)=>{
108
108
  const meta = await chain.head.meta;
109
- return meta.consts.babe ? meta.consts.babe.expectedBlockTime.toNumber() : meta.query.aura ? getAuraSlotDuration(await chain.head.wasm) : 12_000;
109
+ return meta.consts.babe ? meta.consts.babe.expectedBlockTime.toNumber() : meta.query.aura ? getAuraSlotDuration(await chain.head.wasm) : meta.consts.asyncBacking ? meta.consts.asyncBacking.expectedBlockTime.toNumber() : 12_000;
110
110
  };
@@ -27,5 +27,14 @@ export const connectHorizontal = async (parachains)=>{
27
27
  }
28
28
  }
29
29
  });
30
+ const hrmpHeads = await chain.head.read('BTreeMap<u32, H256>', meta.query.parachainSystem.lastHrmpMqcHeads);
31
+ if (hrmpHeads && !process.env.DISABLE_AUTO_HRMP) {
32
+ const existingChannels = Array.from(hrmpHeads.keys()).map((x)=>x.toNumber());
33
+ for (const paraId of Object.keys(parachains).filter((x)=>x !== id)){
34
+ if (!existingChannels.includes(Number(paraId))) {
35
+ chain.submitHorizontalMessages(Number(paraId), []);
36
+ }
37
+ }
38
+ }
30
39
  }
31
40
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks-core",
3
- "version": "0.9.10",
3
+ "version": "0.9.11-1",
4
4
  "author": "Acala Developers <hello@acala.network>",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  "docs:prep": "typedoc"
13
13
  },
14
14
  "dependencies": {
15
- "@acala-network/chopsticks-executor": "0.9.10",
15
+ "@acala-network/chopsticks-executor": "0.9.11-1",
16
16
  "@polkadot/rpc-provider": "^10.11.2",
17
17
  "@polkadot/types": "^10.11.2",
18
18
  "@polkadot/types-codec": "^10.11.2",
@@ -22,18 +22,18 @@
22
22
  "comlink": "^4.4.1",
23
23
  "eventemitter3": "^5.0.1",
24
24
  "lodash": "^4.17.21",
25
- "lru-cache": "^10.1.0",
26
- "pino": "^8.17.2",
27
- "pino-pretty": "^10.3.1",
25
+ "lru-cache": "^10.2.0",
26
+ "pino": "^8.19.0",
27
+ "pino-pretty": "^11.0.0",
28
28
  "rxjs": "^7.8.1",
29
29
  "zod": "^3.22.4"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@swc/cli": "0.1.65",
33
- "@swc/core": "^1.3.105",
34
- "@types/lodash": "^4.14.202",
33
+ "@swc/core": "^1.4.8",
34
+ "@types/lodash": "^4.17.0",
35
35
  "typescript": "^5.3.3",
36
- "vitest": "^1.2.1"
36
+ "vitest": "^1.4.0"
37
37
  },
38
38
  "files": [
39
39
  "dist/esm/**",