@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.
- package/lib/blockchain/block-builder.d.ts +1 -1
- package/lib/blockchain/block-builder.js +47 -14
- package/lib/blockchain/block.js +10 -8
- package/lib/blockchain/head-state.js +12 -17
- package/lib/blockchain/index.d.ts +10 -4
- package/lib/blockchain/index.js +87 -7
- package/lib/blockchain/inherent/index.d.ts +2 -2
- package/lib/blockchain/inherent/para-enter.d.ts +1 -1
- package/lib/blockchain/inherent/parachain/babe-randomness.d.ts +1 -1
- package/lib/blockchain/inherent/parachain/nimbus-author-inherent.d.ts +1 -1
- package/lib/blockchain/inherent/parachain/validation-data.d.ts +4 -10
- package/lib/blockchain/inherent/parachain/validation-data.js +5 -4
- package/lib/blockchain/storage-layer.js +0 -1
- package/lib/blockchain/txpool.d.ts +10 -11
- package/lib/blockchain/txpool.js +84 -22
- package/lib/cli.js +2 -1
- package/lib/rpc/dev/dry-run.d.ts +2 -0
- package/lib/rpc/dev/dry-run.js +75 -0
- package/lib/rpc/{dev.d.ts → dev/index.d.ts} +1 -1
- package/lib/rpc/{dev.js → dev/index.js} +15 -33
- package/lib/rpc/substrate/author.js +0 -1
- package/lib/schema/index.d.ts +2 -2
- package/lib/setup.js +4 -1
- package/lib/utils/decoder.d.ts +5 -4
- package/lib/utils/decoder.js +9 -11
- package/lib/utils/index.d.ts +6 -0
- package/lib/utils/index.js +10 -1
- package/lib/xcm/downward.js +1 -1
- package/lib/xcm/horizontal.js +1 -4
- package/lib/xcm/upward.js +5 -19
- package/package.json +4 -3
- package/template/diff.html +3 -3
|
@@ -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()
|
|
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
|
|
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
|
-
|
|
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
|
|
209
|
-
|
|
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;
|
package/lib/blockchain/block.js
CHANGED
|
@@ -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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
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
|
-
|
|
41
|
-
|
|
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[]
|
|
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
|
}
|
package/lib/blockchain/index.js
CHANGED
|
@@ -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
|
|
125
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
38
|
-
|
|
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
|
}
|
package/lib/blockchain/txpool.js
CHANGED
|
@@ -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
|
-
#
|
|
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
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.#
|
|
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
|
|
58
|
-
const
|
|
59
|
-
if (
|
|
60
|
-
|
|
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
|
|
108
|
+
return count;
|
|
66
109
|
}
|
|
67
|
-
async #
|
|
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
|
-
|
|
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
|
|
72
|
-
const
|
|
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 } =
|
|
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,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,21 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const shared_1 = require("
|
|
4
|
-
const set_storage_1 = require("
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
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
|
|
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;
|
package/lib/schema/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/lib/utils/decoder.d.ts
CHANGED
|
@@ -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) =>
|
|
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) =>
|
|
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)[]>;
|
package/lib/utils/decoder.js
CHANGED
|
@@ -20,13 +20,12 @@ const getCache = (uid) => {
|
|
|
20
20
|
}
|
|
21
21
|
return _CACHE[uid];
|
|
22
22
|
};
|
|
23
|
-
const getStorageEntry =
|
|
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
|
-
|
|
38
|
+
return undefined;
|
|
40
39
|
};
|
|
41
|
-
const decodeKey =
|
|
42
|
-
const
|
|
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 =
|
|
53
|
-
const
|
|
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,
|
|
101
|
-
lodash_1.default.merge(newState,
|
|
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']) {
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -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>;
|
package/lib/utils/index.js
CHANGED
|
@@ -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;
|
package/lib/xcm/downward.js
CHANGED
|
@@ -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
|
-
|
|
26
|
+
parachain.submitDownwardMessages(downwardMessages);
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
29
|
exports.connectDownward = connectDownward;
|
package/lib/xcm/horizontal.js
CHANGED
|
@@ -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
|
-
|
|
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 (
|
|
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
|
|
16
|
-
const
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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",
|
package/template/diff.html
CHANGED
|
@@ -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 =
|
|
151
|
-
const newValue =
|
|
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 =
|
|
153
|
+
const delta = newValue - oldValue
|
|
154
154
|
return (<span className="delta" >{delta > 0 ? '+' : ''}{delta.toLocaleString()}</span>)
|
|
155
155
|
}
|
|
156
156
|
}
|