@acala-network/chopsticks 0.4.1 → 0.5.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.
@@ -2,7 +2,7 @@ import { Header, TransactionValidityError } from '@polkadot/types/interfaces';
2
2
  import { Block, TaskCallResponse } from './block';
3
3
  import { HexString } from '@polkadot/util/types';
4
4
  export declare const newHeader: (head: Block) => Promise<Header>;
5
- export declare const buildBlock: (head: Block, inherents: HexString[], extrinsics: HexString[], onApplyExtrinsicError: (extrinsic: HexString, error: TransactionValidityError) => void) => Promise<[Block, HexString[]]>;
5
+ export declare const buildBlock: (head: Block, inherents: HexString[], extrinsics: HexString[], ump: Record<number, HexString[]>, onApplyExtrinsicError: (extrinsic: HexString, error: TransactionValidityError) => void) => Promise<[Block, HexString[]]>;
6
6
  export declare const dryRunExtrinsic: (head: Block, inherents: HexString[], extrinsic: HexString | {
7
7
  call: HexString;
8
8
  address: string;
@@ -71,8 +71,12 @@ const newHeader = async (head) => {
71
71
  ],
72
72
  },
73
73
  ...consensus.rest,
74
- head.pushStorageLayer().set((0, utils_1.compactHex)(meta.query.randomness.notFirstBlock()), "Deleted" /* StorageValueKind.Deleted */),
75
74
  ];
75
+ if (meta.query.randomness) {
76
+ // TODO: shouldn't modify existing head
77
+ // reset notFirstBlock so randomness will skip validation
78
+ head.pushStorageLayer().set((0, utils_1.compactHex)(meta.query.randomness.notFirstBlock()), "Deleted" /* StorageValueKind.Deleted */);
79
+ }
76
80
  }
77
81
  const header = meta.registry.createType('Header', {
78
82
  parentHash: head.hash,
@@ -98,11 +102,14 @@ const initNewBlock = async (head, header, inherents) => {
98
102
  newBlock.pushStorageLayer().setAll(storageDiff);
99
103
  logger.trace((0, logger_1.truncate)(storageDiff), 'Initialize block');
100
104
  }
105
+ const layers = [];
101
106
  // apply inherents
102
107
  for (const extrinsic of inherents) {
103
108
  try {
104
109
  const { storageDiff } = await newBlock.call('BlockBuilder_apply_extrinsic', [extrinsic]);
105
- newBlock.pushStorageLayer().setAll(storageDiff);
110
+ const layer = newBlock.pushStorageLayer();
111
+ layer.setAll(storageDiff);
112
+ layers.push(layer);
106
113
  logger.trace((0, logger_1.truncate)(storageDiff), 'Applied inherent');
107
114
  }
108
115
  catch (e) {
@@ -110,12 +117,15 @@ const initNewBlock = async (head, header, inherents) => {
110
117
  throw new Error('Failed to apply inherents');
111
118
  }
112
119
  }
113
- return newBlock;
120
+ return {
121
+ block: newBlock,
122
+ layers: layers,
123
+ };
114
124
  };
115
- const buildBlock = async (head, inherents, extrinsics, onApplyExtrinsicError) => {
125
+ const buildBlock = async (head, inherents, extrinsics, ump, onApplyExtrinsicError) => {
116
126
  const registry = await head.registry;
117
127
  const header = await (0, exports.newHeader)(head);
118
- const newBlock = await initNewBlock(head, header, inherents);
128
+ const { block: newBlock } = await initNewBlock(head, header, inherents);
119
129
  logger.info({
120
130
  number: newBlock.number,
121
131
  extrinsicsCount: extrinsics.length,
@@ -123,18 +133,37 @@ const buildBlock = async (head, inherents, extrinsics, onApplyExtrinsicError) =>
123
133
  }, `Try building block #${newBlock.number.toLocaleString()}`);
124
134
  const pendingExtrinsics = [];
125
135
  const includedExtrinsic = [];
136
+ // apply ump via storage override hack
137
+ if (Object.keys(ump).length > 0) {
138
+ const meta = await head.meta;
139
+ const layer = head.pushStorageLayer();
140
+ for (const [paraId, upwardMessages] of Object.entries(ump)) {
141
+ const queueSize = meta.registry.createType('(u32, u32)', [
142
+ upwardMessages.length,
143
+ upwardMessages.map((x) => x.length).reduce((s, i) => s + i, 0),
144
+ ]);
145
+ const messages = meta.registry.createType('Vec<Bytes>', upwardMessages);
146
+ // TODO: make sure we append instead of replace
147
+ layer.setAll([
148
+ [(0, utils_1.compactHex)(meta.query.ump.relayDispatchQueues(paraId)), messages.toHex()],
149
+ [(0, utils_1.compactHex)(meta.query.ump.relayDispatchQueueSize(paraId)), queueSize.toHex()],
150
+ ]);
151
+ }
152
+ logger.trace({
153
+ number: newBlock.number,
154
+ tempHash: newBlock.hash,
155
+ ump,
156
+ }, 'Upward messages');
157
+ const needsDispatch = meta.registry.createType('Vec<u32>', Object.keys(ump));
158
+ layer.set((0, utils_1.compactHex)(meta.query.ump.needsDispatch()), needsDispatch.toHex());
159
+ }
126
160
  // apply extrinsics
127
161
  for (const extrinsic of extrinsics) {
128
162
  try {
129
163
  const { result, storageDiff } = await newBlock.call('BlockBuilder_apply_extrinsic', [extrinsic]);
130
164
  const outcome = registry.createType('ApplyExtrinsicResult', result);
131
165
  if (outcome.isErr) {
132
- if (outcome.asErr.isInvalid && outcome.asErr.asInvalid.isFuture) {
133
- pendingExtrinsics.push(extrinsic);
134
- }
135
- else {
136
- onApplyExtrinsicError(extrinsic, outcome.asErr);
137
- }
166
+ onApplyExtrinsicError(extrinsic, outcome.asErr);
138
167
  continue;
139
168
  }
140
169
  newBlock.pushStorageLayer().setAll(storageDiff);
@@ -176,7 +205,7 @@ exports.buildBlock = buildBlock;
176
205
  const dryRunExtrinsic = async (head, inherents, extrinsic) => {
177
206
  const registry = await head.registry;
178
207
  const header = await (0, exports.newHeader)(head);
179
- const newBlock = await initNewBlock(head, header, inherents);
208
+ const { block: newBlock } = await initNewBlock(head, header, inherents);
180
209
  if (typeof extrinsic !== 'string') {
181
210
  if (!head.chain.mockSignatureHost) {
182
211
  throw new Error('Cannot fake signature because mock signature host is not enabled. Start chain with `mockSignatureHost: true`');
@@ -205,7 +234,11 @@ const dryRunExtrinsic = async (head, inherents, extrinsic) => {
205
234
  exports.dryRunExtrinsic = dryRunExtrinsic;
206
235
  const dryRunInherents = async (head, inherents) => {
207
236
  const header = await (0, exports.newHeader)(head);
208
- const newBlock = await initNewBlock(head, header, inherents);
209
- return Object.entries(await newBlock.storageDiff());
237
+ const { layers } = await initNewBlock(head, header, inherents);
238
+ const stoarge = {};
239
+ for (const layer of layers) {
240
+ await layer.mergeInto(stoarge);
241
+ }
242
+ return Object.entries(stoarge);
210
243
  };
211
244
  exports.dryRunInherents = dryRunInherents;
@@ -31,15 +31,17 @@ class Block {
31
31
  this.#extrinsics = block?.extrinsics;
32
32
  this.#baseStorage = block?.storage ?? new storage_layer_1.RemoteStorageLayer(chain.api, hash, chain.db);
33
33
  this.#storages = [];
34
- const storageDiff = block?.storageDiff || {};
35
- // if code doesn't change then reuse parent block's meta
36
- if (!storageDiff[(0, util_2.stringToHex)(':code')]) {
37
- this.#runtimeVersion = parentBlock?.runtimeVersion;
38
- this.#metadata = parentBlock?.metadata;
39
- this.#registry = parentBlock?.registry;
40
- this.#meta = parentBlock?.meta;
34
+ const storageDiff = block?.storageDiff;
35
+ if (storageDiff) {
36
+ // if code doesn't change then reuse parent block's meta
37
+ if (!storageDiff?.[(0, util_2.stringToHex)(':code')]) {
38
+ this.#runtimeVersion = parentBlock?.runtimeVersion;
39
+ this.#metadata = parentBlock?.metadata;
40
+ this.#registry = parentBlock?.registry;
41
+ this.#meta = parentBlock?.meta;
42
+ }
43
+ this.pushStorageLayer().setAll(storageDiff);
41
44
  }
42
- this.pushStorageLayer().setAll(storageDiff);
43
45
  }
44
46
  get chain() {
45
47
  return this.#chain;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HeadState = exports.randomId = void 0;
4
- const rxjs_1 = require("rxjs");
5
4
  const util_1 = require("@polkadot/util");
6
5
  const logger_1 = require("../logger");
7
6
  const randomId = () => Math.random().toString(36).substring(2);
@@ -47,27 +46,23 @@ class HeadState {
47
46
  async setHead(head) {
48
47
  this.#head = head;
49
48
  for (const cb of Object.values(this.#headListeners)) {
50
- rxjs_1.asapScheduler.schedule(() => {
51
- try {
52
- cb(head);
53
- }
54
- catch (error) {
55
- logger.error(error, 'callback');
56
- }
57
- });
49
+ try {
50
+ await cb(head);
51
+ }
52
+ catch (error) {
53
+ logger.error(error, 'setHead head callback error');
54
+ }
58
55
  }
59
56
  const diff = await this.#head.storageDiff();
60
57
  for (const [keys, cb] of Object.values(this.#storageListeners)) {
61
58
  const changed = keys.filter((key) => diff[key]).map((key) => [key, diff[key]]);
62
59
  if (changed.length > 0) {
63
- rxjs_1.asapScheduler.schedule(() => {
64
- try {
65
- cb(head, changed);
66
- }
67
- catch (error) {
68
- logger.error(error, 'callback');
69
- }
70
- });
60
+ try {
61
+ await cb(head, changed);
62
+ }
63
+ catch (error) {
64
+ logger.error(error, 'setHead storaeg diff callback error');
65
+ }
71
66
  }
72
67
  }
73
68
  Object.assign(this.#oldValues, diff);
@@ -4,7 +4,7 @@ import { HexString } from '@polkadot/util/types';
4
4
  import { RegisteredTypes } from '@polkadot/types/types';
5
5
  import { Api } from '../api';
6
6
  import { Block } from './block';
7
- import { BuildBlockMode, BuildBlockParams, HorizontalMessage, TxPool, UpcomingBlockParams } from './txpool';
7
+ import { BuildBlockMode, BuildBlockParams, DownwardMessage, HorizontalMessage, TxPool } from './txpool';
8
8
  import { HeadState } from './head-state';
9
9
  import { InherentProvider } from './inherent';
10
10
  export interface Options {
@@ -37,8 +37,12 @@ export declare class Blockchain {
37
37
  unregisterBlock(block: Block): void;
38
38
  setHead(block: Block): Promise<void>;
39
39
  submitExtrinsic(extrinsic: HexString): Promise<HexString>;
40
- newBlock(params?: BuildBlockParams): Promise<Block>;
41
- upcomingBlock(params?: UpcomingBlockParams): Promise<Block>;
40
+ submitUpwardMessages(id: number, ump: HexString[]): void;
41
+ submitDownwardMessages(dmp: DownwardMessage[]): void;
42
+ submitHorizontalMessages(id: number, hrmp: HorizontalMessage[]): void;
43
+ newBlock(params?: Partial<BuildBlockParams>): Promise<Block>;
44
+ newBlockWithParams(params: BuildBlockParams): Promise<Block>;
45
+ upcomingBlocks(): Promise<number>;
42
46
  dryRunExtrinsic(extrinsic: HexString | {
43
47
  call: HexString;
44
48
  address: string;
@@ -46,6 +50,8 @@ export declare class Blockchain {
46
50
  outcome: ApplyExtrinsicResult;
47
51
  storageDiff: [HexString, HexString | null][];
48
52
  }>;
49
- dryRunHrmp(hrmp: Record<number, HorizontalMessage[]>): Promise<[HexString, HexString | null][]>;
53
+ dryRunHrmp(hrmp: Record<number, HorizontalMessage[]>, at?: HexString): Promise<[HexString, HexString | null][]>;
54
+ dryRunDmp(dmp: DownwardMessage[], at?: HexString): Promise<[HexString, HexString | null][]>;
55
+ dryRunUmp(ump: Record<number, HexString[]>, at?: HexString): Promise<[HexString, HexString | null][]>;
50
56
  getInherents(): Promise<HexString[]>;
51
57
  }
@@ -6,6 +6,7 @@ const util_1 = require("@polkadot/util");
6
6
  const block_1 = require("./block");
7
7
  const txpool_1 = require("./txpool");
8
8
  const head_state_1 = require("./head-state");
9
+ const utils_1 = require("../utils");
9
10
  const logger_1 = require("../logger");
10
11
  const block_builder_1 = require("./block-builder");
11
12
  const logger = logger_1.defaultLogger.child({ name: 'blockchain' });
@@ -117,12 +118,28 @@ class Blockchain {
117
118
  }
118
119
  throw validity.asErr;
119
120
  }
121
+ submitUpwardMessages(id, ump) {
122
+ this.#txpool.submitUpwardMessages(id, ump);
123
+ logger.debug({ id, ump }, 'submitUpwardMessages');
124
+ }
125
+ submitDownwardMessages(dmp) {
126
+ this.#txpool.submitDownwardMessages(dmp);
127
+ logger.debug({ dmp }, 'submitDownwardMessages');
128
+ }
129
+ submitHorizontalMessages(id, hrmp) {
130
+ this.#txpool.submitHorizontalMessages(id, hrmp);
131
+ logger.debug({ id, hrmp }, 'submitHorizontalMessages');
132
+ }
120
133
  async newBlock(params) {
121
134
  await this.#txpool.buildBlock(params);
122
135
  return this.#head;
123
136
  }
124
- async upcomingBlock(params) {
125
- return this.#txpool.upcomingBlock(params);
137
+ async newBlockWithParams(params) {
138
+ await this.#txpool.buildBlockWithParams(params);
139
+ return this.#head;
140
+ }
141
+ async upcomingBlocks() {
142
+ return this.#txpool.upcomingBlocks();
126
143
  }
127
144
  async dryRunExtrinsic(extrinsic, at) {
128
145
  await this.api.isReady;
@@ -131,20 +148,83 @@ class Blockchain {
131
148
  throw new Error(`Cannot find block ${at}`);
132
149
  }
133
150
  const registry = await head.registry;
134
- const inherents = await this.#inherentProvider.createInherents(head);
151
+ const inherents = await this.#inherentProvider.createInherents(head, {
152
+ transactions: [],
153
+ downwardMessages: [],
154
+ upwardMessages: [],
155
+ horizontalMessages: {},
156
+ });
135
157
  const { result, storageDiff } = await (0, block_builder_1.dryRunExtrinsic)(head, inherents, extrinsic);
136
158
  const outcome = registry.createType('ApplyExtrinsicResult', result);
137
159
  return { outcome, storageDiff };
138
160
  }
139
- async dryRunHrmp(hrmp) {
161
+ async dryRunHrmp(hrmp, at) {
162
+ await this.api.isReady;
163
+ const head = at ? await this.getBlock(at) : this.head;
164
+ if (!head) {
165
+ throw new Error(`Cannot find block ${at}`);
166
+ }
167
+ const inherents = await this.#inherentProvider.createInherents(head, {
168
+ transactions: [],
169
+ downwardMessages: [],
170
+ upwardMessages: [],
171
+ horizontalMessages: hrmp,
172
+ });
173
+ return (0, block_builder_1.dryRunInherents)(head, inherents);
174
+ }
175
+ async dryRunDmp(dmp, at) {
140
176
  await this.api.isReady;
141
- const head = this.head;
142
- const inherents = await this.#inherentProvider.createInherents(head, { horizontalMessages: hrmp });
177
+ const head = at ? await this.getBlock(at) : this.head;
178
+ if (!head) {
179
+ throw new Error(`Cannot find block ${at}`);
180
+ }
181
+ const inherents = await this.#inherentProvider.createInherents(head, {
182
+ transactions: [],
183
+ downwardMessages: dmp,
184
+ upwardMessages: [],
185
+ horizontalMessages: {},
186
+ });
187
+ return (0, block_builder_1.dryRunInherents)(head, inherents);
188
+ }
189
+ async dryRunUmp(ump, at) {
190
+ await this.api.isReady;
191
+ const head = at ? await this.getBlock(at) : this.head;
192
+ if (!head) {
193
+ throw new Error(`Cannot find block ${at}`);
194
+ }
195
+ const meta = await head.meta;
196
+ const needsDispatch = meta.registry.createType('Vec<u32>', Object.keys(ump));
197
+ const stroageValues = [
198
+ [(0, utils_1.compactHex)(meta.query.ump.needsDispatch()), needsDispatch.toHex()],
199
+ ];
200
+ for (const [paraId, messages] of Object.entries(ump)) {
201
+ const upwardMessages = meta.registry.createType('Vec<Bytes>', messages);
202
+ if (upwardMessages.length === 0)
203
+ throw new Error('No upward meesage');
204
+ const queueSize = meta.registry.createType('(u32, u32)', [
205
+ upwardMessages.length,
206
+ upwardMessages.map((x) => x.byteLength).reduce((s, i) => s + i, 0),
207
+ ]);
208
+ stroageValues.push([(0, utils_1.compactHex)(meta.query.ump.relayDispatchQueues(paraId)), upwardMessages.toHex()]);
209
+ stroageValues.push([(0, utils_1.compactHex)(meta.query.ump.relayDispatchQueueSize(paraId)), queueSize.toHex()]);
210
+ }
211
+ head.pushStorageLayer().setAll(stroageValues);
212
+ const inherents = await this.#inherentProvider.createInherents(head, {
213
+ transactions: [],
214
+ downwardMessages: [],
215
+ upwardMessages: [],
216
+ horizontalMessages: {},
217
+ });
143
218
  return (0, block_builder_1.dryRunInherents)(head, inherents);
144
219
  }
145
220
  async getInherents() {
146
221
  await this.api.isReady;
147
- const inherents = await this.#inherentProvider.createInherents(this.head);
222
+ const inherents = await this.#inherentProvider.createInherents(this.head, {
223
+ transactions: [],
224
+ downwardMessages: [],
225
+ upwardMessages: [],
226
+ horizontalMessages: {},
227
+ });
148
228
  return inherents;
149
229
  }
150
230
  }
@@ -6,7 +6,7 @@ export { ParaInherentEnter } from './para-enter';
6
6
  export { SetBabeRandomness } from './parachain/babe-randomness';
7
7
  export { SetNimbusAuthorInherent } from './parachain/nimbus-author-inherent';
8
8
  export interface CreateInherents {
9
- createInherents(parent: Block, params?: BuildBlockParams['inherent']): Promise<HexString[]>;
9
+ createInherents(parent: Block, params: BuildBlockParams): Promise<HexString[]>;
10
10
  }
11
11
  export type InherentProvider = CreateInherents;
12
12
  export declare class SetTimestamp implements InherentProvider {
@@ -15,5 +15,5 @@ export declare class SetTimestamp implements InherentProvider {
15
15
  export declare class InherentProviders implements InherentProvider {
16
16
  #private;
17
17
  constructor(base: InherentProvider, providers: CreateInherents[]);
18
- createInherents(parent: Block, params?: BuildBlockParams['inherent']): Promise<HexString[]>;
18
+ createInherents(parent: Block, params: BuildBlockParams): Promise<HexString[]>;
19
19
  }
@@ -3,5 +3,5 @@ import { Block } from '../block';
3
3
  import { BuildBlockParams } from '../txpool';
4
4
  import { CreateInherents } from '.';
5
5
  export declare class ParaInherentEnter implements CreateInherents {
6
- createInherents(parent: Block, _params?: BuildBlockParams['inherent']): Promise<HexString[]>;
6
+ createInherents(parent: Block, _params: BuildBlockParams): Promise<HexString[]>;
7
7
  }
@@ -3,5 +3,5 @@ import { Block } from '../../block';
3
3
  import { BuildBlockParams } from '../../txpool';
4
4
  import { CreateInherents } from '..';
5
5
  export declare class SetBabeRandomness implements CreateInherents {
6
- createInherents(parent: Block, _params?: BuildBlockParams['inherent']): Promise<HexString[]>;
6
+ createInherents(parent: Block, _params: BuildBlockParams): Promise<HexString[]>;
7
7
  }
@@ -3,5 +3,5 @@ import { Block } from '../../block';
3
3
  import { BuildBlockParams } from '../../txpool';
4
4
  import { CreateInherents } from '..';
5
5
  export declare class SetNimbusAuthorInherent implements CreateInherents {
6
- createInherents(parent: Block, _params?: BuildBlockParams['inherent']): Promise<HexString[]>;
6
+ createInherents(parent: Block, _params: BuildBlockParams): Promise<HexString[]>;
7
7
  }
@@ -1,16 +1,10 @@
1
1
  import { HexString } from '@polkadot/util/types';
2
2
  import { Block } from '../../block';
3
- import { BuildBlockParams } from '../../txpool';
3
+ import { BuildBlockParams, DownwardMessage, HorizontalMessage } from '../../txpool';
4
4
  import { CreateInherents } from '..';
5
5
  export type ValidationData = {
6
- downwardMessages: {
7
- sent_at: number;
8
- msg: HexString;
9
- }[];
10
- horizontalMessages: Record<number, {
11
- sent_at: number;
12
- data: HexString;
13
- }[]>;
6
+ downwardMessages: DownwardMessage[];
7
+ horizontalMessages: Record<number, HorizontalMessage[]>;
14
8
  validationData: {
15
9
  relayParentNumber: number;
16
10
  relayParentStorageRoot: HexString;
@@ -21,5 +15,5 @@ export type ValidationData = {
21
15
  };
22
16
  };
23
17
  export declare class SetValidationData implements CreateInherents {
24
- createInherents(parent: Block, params?: BuildBlockParams['inherent']): Promise<HexString[]>;
18
+ createInherents(parent: Block, params: BuildBlockParams): Promise<HexString[]>;
25
19
  }
@@ -75,12 +75,12 @@ class SetValidationData {
75
75
  // inject downward messages
76
76
  let dmqMqcHeadHash = decoded[dmqMqcHeadKey];
77
77
  if (dmqMqcHeadHash) {
78
- for (const { msg, sentAt } of params?.downwardMessages || []) {
78
+ for (const { msg, sentAt } of params.downwardMessages) {
79
79
  // calculate new hash
80
80
  dmqMqcHeadHash = (0, util_crypto_1.blake2AsHex)((0, util_1.u8aConcat)(meta.registry.createType('Hash', dmqMqcHeadHash).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), (0, util_crypto_1.blake2AsU8a)(meta.registry.createType('Bytes', msg).toU8a(), 256)), 256);
81
81
  downwardMessages.push({
82
82
  msg,
83
- sent_at: sentAt,
83
+ sentAt,
84
84
  });
85
85
  }
86
86
  newEntries.push([dmqMqcHeadKey, dmqMqcHeadHash]);
@@ -92,8 +92,9 @@ class SetValidationData {
92
92
  .createType('Vec<ParaId>', decoded[hrmpEgressChannelIndexKey])
93
93
  .toJSON();
94
94
  const hrmpMessages = {
95
+ // reset values, we just need the keys
95
96
  ...lodash_1.default.mapValues(extrinsic.horizontalMessages, () => []),
96
- ...(params?.horizontalMessages || {}),
97
+ ...params.horizontalMessages,
97
98
  };
98
99
  // inject horizontal messages
99
100
  for (const id of hrmpIngressChannels) {
@@ -120,7 +121,7 @@ class SetValidationData {
120
121
  abridgedHrmp.totalSize = abridgedHrmp.totalSize + bytes.length;
121
122
  paraMessages.push({
122
123
  data,
123
- sent_at: sentAt,
124
+ sentAt,
124
125
  });
125
126
  }
126
127
  horizontalMessages[sender] = paraMessages;
@@ -128,7 +128,6 @@ class StorageLayer {
128
128
  }
129
129
  async getKeysPaged(prefix, pageSize, startKey) {
130
130
  if (!this.#deletedPrefix.some((prefix) => startKey.startsWith(prefix))) {
131
- await this.fold();
132
131
  // TODO: maintain a list of fetched ranges to avoid fetching the same range multiple times
133
132
  const remote = (await this.#parent?.getKeysPaged(prefix, pageSize, startKey)) ?? [];
134
133
  for (const key of remote) {
@@ -1,7 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from 'node:stream';
3
3
  import { HexString } from '@polkadot/util/types';
4
- import { Block } from './block';
5
4
  import { Blockchain } from '.';
6
5
  import { InherentProvider } from './inherent';
7
6
  export declare const APPLY_EXTRINSIC_ERROR = "TxPool::ApplyExtrinsicError";
@@ -19,14 +18,10 @@ export interface HorizontalMessage {
19
18
  data: HexString;
20
19
  }
21
20
  export interface BuildBlockParams {
22
- inherent?: {
23
- downwardMessages?: DownwardMessage[];
24
- horizontalMessages?: Record<number, HorizontalMessage[]>;
25
- };
26
- }
27
- export interface UpcomingBlockParams {
28
- skipCount?: number;
29
- timeout?: number;
21
+ downwardMessages: DownwardMessage[];
22
+ upwardMessages: Record<number, HexString[]>;
23
+ horizontalMessages: Record<number, HorizontalMessage[]>;
24
+ transactions: HexString[];
30
25
  }
31
26
  export declare class TxPool {
32
27
  #private;
@@ -34,6 +29,10 @@ export declare class TxPool {
34
29
  constructor(chain: Blockchain, inherentProvider: InherentProvider, mode?: BuildBlockMode);
35
30
  get pendingExtrinsics(): HexString[];
36
31
  submitExtrinsic(extrinsic: HexString): void;
37
- buildBlock(params?: BuildBlockParams): Promise<void>;
38
- upcomingBlock(params?: UpcomingBlockParams): Promise<Block>;
32
+ submitUpwardMessages(id: number, ump: HexString[]): void;
33
+ submitDownwardMessages(dmp: DownwardMessage[]): void;
34
+ submitHorizontalMessages(id: number, hrmp: HorizontalMessage[]): void;
35
+ buildBlockWithParams(params: BuildBlockParams): Promise<void>;
36
+ buildBlock(params?: Partial<BuildBlockParams>): Promise<void>;
37
+ upcomingBlocks(): Promise<number>;
39
38
  }
@@ -4,10 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TxPool = exports.BuildBlockMode = exports.APPLY_EXTRINSIC_ERROR = void 0;
7
- const rxjs_1 = require("rxjs");
8
7
  const node_stream_1 = require("node:stream");
9
- const operators_1 = require("rxjs/operators");
10
8
  const lodash_1 = __importDefault(require("lodash"));
9
+ const utils_1 = require("../utils");
11
10
  const block_builder_1 = require("./block-builder");
12
11
  exports.APPLY_EXTRINSIC_ERROR = 'TxPool::ApplyExtrinsicError';
13
12
  var BuildBlockMode;
@@ -19,14 +18,16 @@ var BuildBlockMode;
19
18
  class TxPool {
20
19
  #chain;
21
20
  #pool = [];
21
+ #ump = {};
22
+ #dmp = [];
23
+ #hrmp = {};
22
24
  #mode;
23
25
  #inherentProvider;
26
+ #pendingBlocks = [];
24
27
  event = new node_stream_1.EventEmitter();
25
- #last;
26
- #lastBuildBlockPromise = Promise.resolve();
28
+ #isBuilding = false;
27
29
  constructor(chain, inherentProvider, mode = BuildBlockMode.Batch) {
28
30
  this.#chain = chain;
29
- this.#last = new rxjs_1.BehaviorSubject(chain.head);
30
31
  this.#mode = mode;
31
32
  this.#inherentProvider = inherentProvider;
32
33
  }
@@ -35,6 +36,27 @@ class TxPool {
35
36
  }
36
37
  submitExtrinsic(extrinsic) {
37
38
  this.#pool.push(extrinsic);
39
+ this.#maybeBuildBlock();
40
+ }
41
+ submitUpwardMessages(id, ump) {
42
+ if (!this.#ump[id]) {
43
+ this.#ump[id] = [];
44
+ }
45
+ this.#ump[id].push(...ump);
46
+ this.#maybeBuildBlock();
47
+ }
48
+ submitDownwardMessages(dmp) {
49
+ this.#dmp.push(...dmp);
50
+ this.#maybeBuildBlock();
51
+ }
52
+ submitHorizontalMessages(id, hrmp) {
53
+ if (!this.#hrmp[id]) {
54
+ this.#hrmp[id] = [];
55
+ }
56
+ this.#hrmp[id].push(...hrmp);
57
+ this.#maybeBuildBlock();
58
+ }
59
+ #maybeBuildBlock() {
38
60
  switch (this.#mode) {
39
61
  case BuildBlockMode.Batch:
40
62
  this.#batchBuildBlock();
@@ -48,33 +70,73 @@ class TxPool {
48
70
  }
49
71
  }
50
72
  #batchBuildBlock = lodash_1.default.debounce(this.buildBlock, 100, { maxWait: 1000 });
73
+ async buildBlockWithParams(params) {
74
+ this.#pendingBlocks.push({
75
+ params,
76
+ deferred: (0, utils_1.defer)(),
77
+ });
78
+ this.#buildBlockIfNeeded();
79
+ await this.upcomingBlocks();
80
+ }
51
81
  async buildBlock(params) {
52
- const last = this.#lastBuildBlockPromise;
53
- this.#lastBuildBlockPromise = this.#buildBlock(last, params);
54
- await this.#lastBuildBlockPromise;
55
- this.#last.next(this.#chain.head);
82
+ const transactions = params?.transactions || this.#pool.splice(0);
83
+ const upwardMessages = params?.upwardMessages || { ...this.#ump };
84
+ const downwardMessages = params?.downwardMessages || this.#dmp.splice(0);
85
+ const horizontalMessages = params?.horizontalMessages || { ...this.#hrmp };
86
+ if (!params?.upwardMessages) {
87
+ for (const id of Object.keys(this.#ump)) {
88
+ delete this.#ump[id];
89
+ }
90
+ }
91
+ if (!params?.horizontalMessages) {
92
+ for (const id of Object.keys(this.#hrmp)) {
93
+ delete this.#hrmp[id];
94
+ }
95
+ }
96
+ await this.buildBlockWithParams({
97
+ transactions,
98
+ upwardMessages,
99
+ downwardMessages,
100
+ horizontalMessages,
101
+ });
56
102
  }
57
- async upcomingBlock(params) {
58
- const { skipCount, timeout: millisecs } = { skipCount: 0, ...(params || {}) };
59
- if (skipCount < 0)
60
- throw new Error('skipCount needs to be greater or equal to 0');
61
- let stream$ = this.#last.pipe();
62
- if (millisecs) {
63
- stream$ = stream$.pipe((0, operators_1.timeout)(millisecs));
103
+ async upcomingBlocks() {
104
+ const count = this.#pendingBlocks.length;
105
+ if (count > 0) {
106
+ await this.#pendingBlocks[count - 1].deferred.promise;
64
107
  }
65
- return (0, rxjs_1.firstValueFrom)(stream$.pipe((0, operators_1.skip)(1 + skipCount), (0, operators_1.take)(1)));
108
+ return count;
66
109
  }
67
- async #buildBlock(wait, params) {
110
+ async #buildBlockIfNeeded() {
111
+ if (this.#isBuilding)
112
+ return;
113
+ if (this.#pendingBlocks.length === 0)
114
+ return;
115
+ this.#isBuilding = true;
116
+ try {
117
+ await this.#buildBlock();
118
+ }
119
+ finally {
120
+ this.#isBuilding = false;
121
+ this.#buildBlockIfNeeded();
122
+ }
123
+ }
124
+ async #buildBlock() {
68
125
  await this.#chain.api.isReady;
69
- await wait.catch(() => { }); // ignore error
126
+ const pending = this.#pendingBlocks[0];
127
+ if (!pending) {
128
+ throw new Error('Unreachable');
129
+ }
130
+ const { params, deferred } = pending;
70
131
  const head = this.#chain.head;
71
- const extrinsics = this.#pool.splice(0);
72
- const inherents = await this.#inherentProvider.createInherents(head, params?.inherent);
73
- const [newBlock, pendingExtrinsics] = await (0, block_builder_1.buildBlock)(head, inherents, extrinsics, (extrinsic, error) => {
132
+ const inherents = await this.#inherentProvider.createInherents(head, params);
133
+ const [newBlock, pendingExtrinsics] = await (0, block_builder_1.buildBlock)(head, inherents, params.transactions, params.upwardMessages, (extrinsic, error) => {
74
134
  this.event.emit(exports.APPLY_EXTRINSIC_ERROR, [extrinsic, error]);
75
135
  });
76
136
  this.#pool.push(...pendingExtrinsics);
77
137
  await this.#chain.setHead(newBlock);
138
+ this.#pendingBlocks.shift();
139
+ deferred.resolve();
78
140
  }
79
141
  }
80
142
  exports.TxPool = TxPool;
package/lib/cli.js CHANGED
@@ -40,6 +40,7 @@ const defaultOptions = {
40
40
  },
41
41
  block: {
42
42
  desc: 'Block hash or block number. Default to latest block',
43
+ string: true,
43
44
  },
44
45
  'wasm-override': {
45
46
  desc: 'Path to wasm override',
@@ -146,7 +147,7 @@ const defaultOptions = {
146
147
  ...defaultOptions,
147
148
  }), async (argv) => {
148
149
  const context = await (0, _1.setup)(await processArgv(argv));
149
- const { storage, decodedKey } = await (0, decoder_1.decodeKey)(context.chain.head, argv.key);
150
+ const { storage, decodedKey } = (0, decoder_1.decodeKey)(await context.chain.head.meta, context.chain.head, argv.key);
150
151
  if (storage && decodedKey) {
151
152
  console.log(`${storage.section}.${storage.method}`, decodedKey.args.map((x) => JSON.stringify(x.toHuman())).join(', '));
152
153
  }
@@ -0,0 +1,2 @@
1
+ import { Handler } from '../shared';
2
+ export declare const dev_dryRun: Handler;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.dev_dryRun = void 0;
7
+ const zod_1 = __importDefault(require("zod"));
8
+ const decoder_1 = require("../../utils/decoder");
9
+ const generate_html_diff_1 = require("../../utils/generate-html-diff");
10
+ const zHex = zod_1.default.custom((val) => /^0x\w+$/.test(val));
11
+ const zHash = zod_1.default.string().length(66).and(zHex);
12
+ const zParaId = zod_1.default.string().regex(/^\d+$/).transform(Number);
13
+ const dryRunSchema = zod_1.default.object({
14
+ raw: zod_1.default.boolean().optional(),
15
+ html: zod_1.default.boolean().optional(),
16
+ extrinsic: zHex
17
+ .or(zod_1.default.object({
18
+ call: zHex,
19
+ address: zHex,
20
+ }))
21
+ .optional(),
22
+ hrmp: zod_1.default
23
+ .record(zParaId, zod_1.default
24
+ .array(zod_1.default.object({
25
+ sentAt: zod_1.default.number(),
26
+ data: zHex,
27
+ }))
28
+ .min(1))
29
+ .optional(),
30
+ dmp: zod_1.default
31
+ .array(zod_1.default.object({
32
+ sentAt: zod_1.default.number(),
33
+ msg: zHex,
34
+ }))
35
+ .min(1)
36
+ .optional(),
37
+ ump: zod_1.default.record(zParaId, zod_1.default.array(zHex).min(1)).optional(),
38
+ at: zHash.optional(),
39
+ });
40
+ const dev_dryRun = async (context, [params]) => {
41
+ const { html, extrinsic, hrmp, dmp, ump, raw, at } = dryRunSchema.parse(params);
42
+ const dryRun = async () => {
43
+ if (extrinsic) {
44
+ const { outcome, storageDiff } = await context.chain.dryRunExtrinsic(extrinsic, at);
45
+ if (outcome.isErr) {
46
+ throw new Error(outcome.asErr.toString());
47
+ }
48
+ return storageDiff;
49
+ }
50
+ if (hrmp) {
51
+ return context.chain.dryRunHrmp(hrmp, at);
52
+ }
53
+ if (dmp) {
54
+ return context.chain.dryRunDmp(dmp, at);
55
+ }
56
+ if (ump) {
57
+ return context.chain.dryRunUmp(ump, at);
58
+ }
59
+ throw new Error('No extrinsic to run');
60
+ };
61
+ const storageDiff = await dryRun();
62
+ if (html) {
63
+ return (0, generate_html_diff_1.generateHtmlDiff)(context.chain.head, storageDiff);
64
+ }
65
+ if (raw) {
66
+ return storageDiff;
67
+ }
68
+ const [oldData, newData, delta] = await (0, decoder_1.decodeStorageDiff)(context.chain.head, storageDiff);
69
+ return {
70
+ old: oldData,
71
+ new: newData,
72
+ delta,
73
+ };
74
+ };
75
+ exports.dev_dryRun = dev_dryRun;
@@ -1,3 +1,3 @@
1
- import { Handlers } from './shared';
1
+ import { Handlers } from '../shared';
2
2
  declare const handlers: Handlers;
3
3
  export default handlers;
@@ -1,21 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const shared_1 = require("./shared");
4
- const set_storage_1 = require("../utils/set-storage");
5
- const decoder_1 = require("../utils/decoder");
6
- const logger_1 = require("../logger");
7
- const generate_html_diff_1 = require("../utils/generate-html-diff");
8
- const time_travel_1 = require("../utils/time-travel");
3
+ const shared_1 = require("../shared");
4
+ const set_storage_1 = require("../../utils/set-storage");
5
+ const logger_1 = require("../../logger");
6
+ const dry_run_1 = require("./dry-run");
7
+ const time_travel_1 = require("../../utils/time-travel");
9
8
  const logger = logger_1.defaultLogger.child({ name: 'rpc-dev' });
10
9
  const handlers = {
11
10
  dev_newBlock: async (context, [param]) => {
12
- const { count, to, hrmp } = param || {};
11
+ const { count, to, hrmp, ump, dmp, transactions } = param || {};
13
12
  const now = context.chain.head.number;
14
13
  const diff = to ? to - now : count;
15
14
  const finalCount = diff > 0 ? diff : 1;
16
15
  let finalHash;
17
16
  for (let i = 0; i < finalCount; i++) {
18
- const block = await context.chain.newBlock({ inherent: { horizontalMessages: hrmp || [] } }).catch((error) => {
17
+ const block = await context.chain
18
+ .newBlock({
19
+ transactions,
20
+ horizontalMessages: hrmp,
21
+ upwardMessages: ump,
22
+ downwardMessages: dmp,
23
+ })
24
+ .catch((error) => {
19
25
  throw new shared_1.ResponseError(1, error.toString());
20
26
  });
21
27
  logger.debug({ hash: block.hash }, 'dev_newBlock');
@@ -41,31 +47,6 @@ const handlers = {
41
47
  await (0, time_travel_1.timeTravel)(context.chain, timestamp);
42
48
  return timestamp;
43
49
  },
44
- dev_dryRun: async (context, [{ html, extrinsic, hrmp, raw }]) => {
45
- const dryRun = async () => {
46
- if (extrinsic) {
47
- const { outcome, storageDiff } = await context.chain.dryRunExtrinsic(extrinsic);
48
- if (outcome.isErr) {
49
- throw new Error(outcome.asErr.toString());
50
- }
51
- return storageDiff;
52
- }
53
- return context.chain.dryRunHrmp(hrmp);
54
- };
55
- const storageDiff = await dryRun();
56
- if (html) {
57
- return (0, generate_html_diff_1.generateHtmlDiff)(context.chain.head, storageDiff);
58
- }
59
- if (raw) {
60
- return storageDiff;
61
- }
62
- const [oldData, newData, delta] = await (0, decoder_1.decodeStorageDiff)(context.chain.head, storageDiff);
63
- return {
64
- old: oldData,
65
- new: newData,
66
- delta,
67
- };
68
- },
69
50
  dev_setHead: async (context, [hashOrNumber]) => {
70
51
  let block;
71
52
  if (typeof hashOrNumber === 'number') {
@@ -81,5 +62,6 @@ const handlers = {
81
62
  await context.chain.setHead(block);
82
63
  return block.hash;
83
64
  },
65
+ dev_dryRun: dry_run_1.dev_dryRun,
84
66
  };
85
67
  exports.default = handlers;
@@ -31,7 +31,6 @@ const handlers = {
31
31
  if (!extrisnics.includes(extrinsic))
32
32
  return;
33
33
  logger.debug({ block: block.hash }, 'author_extrinsicUpdate');
34
- // for now just assume tx is always included on next block
35
34
  callback({
36
35
  InBlock: block.hash,
37
36
  });
@@ -134,6 +134,7 @@ export declare const configSchema: z.ZodObject<{
134
134
  'registered-types': z.ZodOptional<z.ZodAny>;
135
135
  }, "strict", z.ZodTypeAny, {
136
136
  timestamp?: number | undefined;
137
+ block?: string | number | undefined;
137
138
  db?: string | undefined;
138
139
  genesis?: string | {
139
140
  name: string;
@@ -151,7 +152,6 @@ export declare const configSchema: z.ZodObject<{
151
152
  } | undefined;
152
153
  port?: number | undefined;
153
154
  endpoint?: string | undefined;
154
- block?: string | number | undefined;
155
155
  'build-block-mode'?: BuildBlockMode | undefined;
156
156
  'import-storage'?: any;
157
157
  'mock-signature-host'?: boolean | undefined;
@@ -159,6 +159,7 @@ export declare const configSchema: z.ZodObject<{
159
159
  'registered-types'?: any;
160
160
  }, {
161
161
  timestamp?: number | undefined;
162
+ block?: string | number | undefined;
162
163
  db?: string | undefined;
163
164
  genesis?: string | {
164
165
  name: string;
@@ -176,7 +177,6 @@ export declare const configSchema: z.ZodObject<{
176
177
  } | undefined;
177
178
  port?: number | undefined;
178
179
  endpoint?: string | undefined;
179
- block?: string | number | undefined;
180
180
  'build-block-mode'?: BuildBlockMode | undefined;
181
181
  'import-storage'?: any;
182
182
  'mock-signature-host'?: boolean | undefined;
package/lib/setup.js CHANGED
@@ -30,11 +30,14 @@ const setup = async (argv) => {
30
30
  if (argv.block == null) {
31
31
  blockHash = await api.getBlockHash();
32
32
  }
33
+ else if (typeof argv.block === 'string' && argv.block.startsWith('0x')) {
34
+ blockHash = argv.block;
35
+ }
33
36
  else if (Number.isInteger(+argv.block)) {
34
37
  blockHash = await api.getBlockHash(Number(argv.block));
35
38
  }
36
39
  else {
37
- blockHash = argv.block;
40
+ throw new Error(`Invalid block number or hash: ${argv.block}`);
38
41
  }
39
42
  logger_1.defaultLogger.debug({ ...argv, blockHash }, 'Args');
40
43
  let db;
@@ -1,17 +1,18 @@
1
1
  import '@polkadot/types-codec';
2
2
  import { Block } from '../blockchain/block';
3
+ import { DecoratedMeta } from '@polkadot/types/metadata/decorate/types';
3
4
  import { HexString } from '@polkadot/util/types';
4
5
  import { StorageEntry } from '@polkadot/types/primitive/types';
5
6
  import { StorageKey } from '@polkadot/types';
6
- export declare const decodeKey: (block: Block, key: HexString) => Promise<{
7
+ export declare const decodeKey: (meta: DecoratedMeta, block: Block, key: HexString) => {
7
8
  storage?: StorageEntry | undefined;
8
9
  decodedKey?: StorageKey<import("@polkadot/types-codec/types").AnyTuple> | undefined;
9
- }>;
10
- export declare const decodeKeyValue: (block: Block, key: HexString, value?: HexString | null) => Promise<{
10
+ };
11
+ export declare const decodeKeyValue: (meta: DecoratedMeta, block: Block, key: HexString, value?: HexString | null) => {
11
12
  [x: string]: `0x${string}` | null | undefined;
12
13
  } | {
13
14
  [x: string]: {
14
15
  [x: string]: import("@polkadot/types-codec/types").AnyJson;
15
16
  };
16
- }>;
17
+ };
17
18
  export declare const decodeStorageDiff: (block: Block, diff: [HexString, HexString | null][]) => Promise<({} | undefined)[]>;
@@ -20,13 +20,12 @@ const getCache = (uid) => {
20
20
  }
21
21
  return _CACHE[uid];
22
22
  };
23
- const getStorageEntry = async (block, key) => {
23
+ const getStorageEntry = (meta, block, key) => {
24
24
  const cache = getCache(block.chain.uid);
25
25
  for (const [prefix, storageEntry] of Object.entries(cache)) {
26
26
  if (key.startsWith(prefix))
27
27
  return storageEntry;
28
28
  }
29
- const meta = await block.meta;
30
29
  for (const module of Object.values(meta.query)) {
31
30
  for (const storage of Object.values(module)) {
32
31
  const keyPrefix = (0, util_1.u8aToHex)(storage.keyPrefix());
@@ -36,11 +35,10 @@ const getStorageEntry = async (block, key) => {
36
35
  }
37
36
  }
38
37
  }
39
- throw new Error(`Cannot find key ${key}`);
38
+ return undefined;
40
39
  };
41
- const decodeKey = async (block, key) => {
42
- const meta = await block.meta;
43
- const storage = await getStorageEntry(block, key).catch(() => undefined);
40
+ const decodeKey = (meta, block, key) => {
41
+ const storage = getStorageEntry(meta, block, key);
44
42
  const decodedKey = meta.registry.createType('StorageKey', key);
45
43
  if (storage) {
46
44
  decodedKey.setMeta(storage.meta);
@@ -49,9 +47,8 @@ const decodeKey = async (block, key) => {
49
47
  return {};
50
48
  };
51
49
  exports.decodeKey = decodeKey;
52
- const decodeKeyValue = async (block, key, value) => {
53
- const meta = await block.meta;
54
- const { storage, decodedKey } = await (0, exports.decodeKey)(block, key);
50
+ const decodeKeyValue = (meta, block, key, value) => {
51
+ const { storage, decodedKey } = (0, exports.decodeKey)(meta, block, key);
55
52
  if (!storage || !decodedKey) {
56
53
  return { [key]: value };
57
54
  }
@@ -96,9 +93,10 @@ exports.decodeKeyValue = decodeKeyValue;
96
93
  const decodeStorageDiff = async (block, diff) => {
97
94
  const oldState = {};
98
95
  const newState = {};
96
+ const meta = await block.meta;
99
97
  for (const [key, value] of diff) {
100
- lodash_1.default.merge(oldState, await (0, exports.decodeKeyValue)(block, key, (await block.get(key))));
101
- lodash_1.default.merge(newState, await (0, exports.decodeKeyValue)(block, key, value));
98
+ lodash_1.default.merge(oldState, (0, exports.decodeKeyValue)(meta, block, key, (await block.get(key))));
99
+ lodash_1.default.merge(newState, (0, exports.decodeKeyValue)(meta, block, key, value));
102
100
  }
103
101
  const oldStateWithoutEvents = lodash_1.default.cloneDeep(oldState);
104
102
  if (oldStateWithoutEvents['system']?.['events']) {
@@ -8,3 +8,9 @@ export declare function fetchKeysToArray(getKeys: GetKeys): Promise<StorageKey<a
8
8
  export declare const compactHex: (value: Uint8Array) => HexString;
9
9
  export declare const getParaId: (chain: Blockchain) => Promise<import("@polkadot/types").u32>;
10
10
  export declare const isUrl: (url: string) => boolean;
11
+ export type Deferred<T> = {
12
+ resolve: (value: T | PromiseLike<T>) => void;
13
+ reject: (reason?: any) => void;
14
+ promise: Promise<T>;
15
+ };
16
+ export declare function defer<T>(): Deferred<T>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUrl = exports.getParaId = exports.compactHex = exports.fetchKeysToArray = exports.fetchKeys = void 0;
3
+ exports.defer = exports.isUrl = exports.getParaId = exports.compactHex = exports.fetchKeysToArray = exports.fetchKeys = void 0;
4
4
  const util_1 = require("@polkadot/util");
5
5
  async function fetchKeys(getKeys, processKey) {
6
6
  const processKeys = async (keys) => {
@@ -48,3 +48,12 @@ const isUrl = (url) => {
48
48
  }
49
49
  };
50
50
  exports.isUrl = isUrl;
51
+ function defer() {
52
+ const deferred = {};
53
+ deferred.promise = new Promise((resolve, reject) => {
54
+ deferred.resolve = resolve;
55
+ deferred.reject = reject;
56
+ });
57
+ return deferred;
58
+ }
59
+ exports.defer = defer;
@@ -23,7 +23,7 @@ const connectDownward = async (relaychain, parachain) => {
23
23
  if (downwardMessages.length === 0)
24
24
  return;
25
25
  _1.logger.debug({ downwardMessages }, 'downward_message');
26
- await parachain.newBlock({ inherent: { downwardMessages } });
26
+ parachain.submitDownwardMessages(downwardMessages);
27
27
  });
28
28
  };
29
29
  exports.connectDownward = connectDownward;
@@ -18,12 +18,9 @@ const connectHorizontal = async (parachains) => {
18
18
  .toJSON();
19
19
  _1.logger.info({ outboundHrmpMessage }, 'outboundHrmpMessage');
20
20
  for (const { recipient, data } of outboundHrmpMessage) {
21
- const horizontalMessages = {
22
- [Number(id)]: [{ sentAt: head.number, data }],
23
- };
24
21
  const receiver = parachains[recipient];
25
22
  if (receiver) {
26
- await receiver.newBlock({ inherent: { horizontalMessages } });
23
+ receiver.submitHorizontalMessages(Number(id), [{ sentAt: head.number, data }]);
27
24
  }
28
25
  }
29
26
  });
package/lib/xcm/upward.js CHANGED
@@ -3,33 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.connectUpward = void 0;
4
4
  const util_1 = require("@polkadot/util");
5
5
  const utils_1 = require("../utils");
6
- const _1 = require(".");
7
6
  const connectUpward = async (parachain, relaychain) => {
8
7
  const meta = await parachain.head.meta;
9
- const paraId = await (0, utils_1.getParaId)(parachain);
8
+ const paraId = (await (0, utils_1.getParaId)(parachain)).toNumber();
10
9
  const upwardMessagesKey = (0, utils_1.compactHex)(meta.query.parachainSystem.upwardMessages());
11
- await parachain.headState.subscribeStorage([upwardMessagesKey], async (head, pairs) => {
10
+ await parachain.headState.subscribeStorage([upwardMessagesKey], async (_head, pairs) => {
12
11
  const value = pairs[0][1];
13
12
  if (!value)
14
13
  return;
15
- const parachainMeta = await head.meta;
16
- const relaychainMeta = await relaychain.head.meta;
17
- const upwardMessages = parachainMeta.registry.createType('Vec<Bytes>', (0, util_1.hexToU8a)(value));
14
+ const meta = await relaychain.head.meta;
15
+ const upwardMessages = meta.registry.createType('Vec<Bytes>', (0, util_1.hexToU8a)(value));
18
16
  if (upwardMessages.length === 0)
19
17
  return;
20
- const queueSize = parachainMeta.registry.createType('(u32, u32)', [
21
- upwardMessages.length,
22
- upwardMessages.map((x) => x.byteLength).reduce((s, i) => s + i, 0),
23
- ]);
24
- const needsDispatch = parachainMeta.registry.createType('Vec<u32>', [paraId]);
25
- _1.logger.debug({ [paraId.toNumber()]: upwardMessages.toJSON(), queueSize: queueSize.toJSON() }, 'upward_message');
26
- // TODO: make sure we append instead of replace
27
- relaychain.head.pushStorageLayer().setAll([
28
- [(0, utils_1.compactHex)(relaychainMeta.query.ump.needsDispatch()), needsDispatch.toHex()],
29
- [(0, utils_1.compactHex)(relaychainMeta.query.ump.relayDispatchQueues(paraId)), upwardMessages.toHex()],
30
- [(0, utils_1.compactHex)(relaychainMeta.query.ump.relayDispatchQueueSize(paraId)), queueSize.toHex()],
31
- ]);
32
- await relaychain.newBlock();
18
+ relaychain.submitUpwardMessages(paraId, upwardMessages.map((x) => x.toHex()));
33
19
  });
34
20
  };
35
21
  exports.connectUpward = connectUpward;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "main": "./lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "author": "Bryan Chen <xlchen1291@gmail.com>",
@@ -12,7 +12,7 @@
12
12
  "build": "rm -rf lib && tsc -p ./tsconfig.json",
13
13
  "test": "vitest run",
14
14
  "test:watch": "vitest",
15
- "script:start": "cd ../..; ts-node packages/chopsticks/src/cli.ts",
15
+ "script:start": "cd ../..; ts-node --transpile-only packages/chopsticks/src/cli.ts",
16
16
  "script:run": "LOG_LEVEL=trace ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/dev.yml",
17
17
  "dev:karura": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/karura.yml",
18
18
  "dev:acala": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/acala.yml",
@@ -20,7 +20,7 @@
20
20
  "dev:moonbeam": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/moonbeam.yml"
21
21
  },
22
22
  "dependencies": {
23
- "@acala-network/chopsticks-executor": "0.4.1",
23
+ "@acala-network/chopsticks-executor": "0.5.0",
24
24
  "@polkadot/api": "^9.14.2",
25
25
  "@polkadot/rpc-provider": "^9.14.2",
26
26
  "@polkadot/types": "^9.14.2",
@@ -35,6 +35,7 @@
35
35
  "pino": "^8.11.0",
36
36
  "pino-pretty": "^9.4.0",
37
37
  "reflect-metadata": "^0.1.13",
38
+ "rxjs": "^7.8.0",
38
39
  "sqlite3": "^5.1.4",
39
40
  "typeorm": "^0.3.12",
40
41
  "ws": "^8.12.1",
@@ -147,10 +147,10 @@
147
147
 
148
148
  function renderDelta(value) {
149
149
  if (/^\d+(,\d+)*$/.test(value[0]) && /^\d+(,\d+)*$/.test(value[1])) {
150
- const oldValue = parseInt(value[0].replace(/,/g, ''))
151
- const newValue = parseInt(value[1].replace(/,/g, ''))
150
+ const oldValue = BigInt(value[0].replace(/,/g, ''))
151
+ const newValue = BigInt(value[1].replace(/,/g, ''))
152
152
  if (oldValue > 0 && newValue > 0) {
153
- const delta = Number(newValue - oldValue)
153
+ const delta = newValue - oldValue
154
154
  return (<span className="delta" >{delta > 0 ? '+' : ''}{delta.toLocaleString()}</span>)
155
155
  }
156
156
  }