@acala-network/chopsticks 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/api.d.ts +3 -2
- package/dist/api.js +15 -20
- package/dist/blockchain/block-builder.d.ts +5 -0
- package/dist/blockchain/block-builder.js +168 -0
- package/dist/blockchain/block.d.ts +6 -4
- package/dist/blockchain/block.js +22 -23
- package/dist/blockchain/head-state.d.ts +4 -2
- package/dist/blockchain/head-state.js +13 -7
- package/dist/blockchain/index.d.ts +13 -8
- package/dist/blockchain/index.js +44 -26
- package/dist/blockchain/inherent/index.d.ts +19 -0
- package/dist/blockchain/inherent/index.js +36 -0
- package/dist/blockchain/inherent/para-enter.d.ts +7 -0
- package/dist/blockchain/inherent/para-enter.js +33 -0
- package/dist/blockchain/inherent/parachain/babe-randomness.d.ts +7 -0
- package/dist/blockchain/inherent/parachain/babe-randomness.js +15 -0
- package/dist/blockchain/inherent/parachain/nimbus-author-inherent.d.ts +7 -0
- package/dist/blockchain/inherent/parachain/nimbus-author-inherent.js +15 -0
- package/dist/blockchain/inherent/parachain/validation-data.d.ts +25 -0
- package/dist/blockchain/{inherents.js → inherent/parachain/validation-data.js} +77 -46
- package/dist/blockchain/txpool.d.ts +17 -2
- package/dist/blockchain/txpool.js +11 -107
- package/dist/dry-run.d.ts +2 -0
- package/dist/dry-run.js +30 -0
- package/dist/executor.d.ts +17 -3
- package/dist/executor.js +43 -3
- package/dist/executor.test.js +16 -9
- package/dist/genesis-provider.d.ts +5 -0
- package/dist/genesis-provider.js +15 -3
- package/dist/index.d.ts +1 -18
- package/dist/index.js +79 -148
- package/dist/rpc/dev.js +39 -2
- package/dist/rpc/shared.d.ts +0 -4
- package/dist/rpc/substrate/author.d.ts +1 -1
- package/dist/rpc/substrate/author.js +7 -2
- package/dist/rpc/substrate/chain.js +2 -2
- package/dist/rpc/substrate/state.js +1 -1
- package/dist/rpc/substrate/system.js +3 -3
- package/dist/run-block.d.ts +2 -0
- package/dist/run-block.js +47 -0
- package/dist/schema/index.js +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/server.js +26 -11
- package/dist/setup-with-server.d.ts +8 -0
- package/dist/setup-with-server.js +23 -0
- package/dist/setup.d.ts +10 -0
- package/dist/setup.js +67 -0
- package/dist/utils/decoder.d.ts +17 -0
- package/dist/utils/decoder.js +101 -0
- package/dist/utils/generate-html-diff.d.ts +4 -0
- package/dist/utils/generate-html-diff.js +20 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +9 -1
- package/dist/utils/open-html.d.ts +1 -0
- package/dist/utils/open-html.js +9 -0
- package/dist/utils/proof.d.ts +10 -2
- package/dist/utils/proof.js +12 -8
- package/dist/utils/set-storage.d.ts +2 -1
- package/dist/utils/time-travel.d.ts +5 -0
- package/dist/utils/time-travel.js +64 -0
- package/dist/xcm/index.d.ts +3 -0
- package/dist/xcm/index.js +67 -0
- package/package.json +10 -7
- package/dist/bindings.d.ts +0 -2
- package/dist/bindings.js +0 -31
- package/dist/blockchain/inherents.d.ts +0 -24
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InherentProviders = exports.SetTimestamp = exports.SetNimbusAuthorInherent = exports.SetBabeRandomness = exports.ParaInherentEnter = exports.SetValidationData = void 0;
|
|
4
|
+
const types_1 = require("@polkadot/types");
|
|
5
|
+
const time_travel_1 = require("../../utils/time-travel");
|
|
6
|
+
var validation_data_1 = require("./parachain/validation-data");
|
|
7
|
+
Object.defineProperty(exports, "SetValidationData", { enumerable: true, get: function () { return validation_data_1.SetValidationData; } });
|
|
8
|
+
var para_enter_1 = require("./para-enter");
|
|
9
|
+
Object.defineProperty(exports, "ParaInherentEnter", { enumerable: true, get: function () { return para_enter_1.ParaInherentEnter; } });
|
|
10
|
+
var babe_randomness_1 = require("./parachain/babe-randomness");
|
|
11
|
+
Object.defineProperty(exports, "SetBabeRandomness", { enumerable: true, get: function () { return babe_randomness_1.SetBabeRandomness; } });
|
|
12
|
+
var nimbus_author_inherent_1 = require("./parachain/nimbus-author-inherent");
|
|
13
|
+
Object.defineProperty(exports, "SetNimbusAuthorInherent", { enumerable: true, get: function () { return nimbus_author_inherent_1.SetNimbusAuthorInherent; } });
|
|
14
|
+
class SetTimestamp {
|
|
15
|
+
async createInherents(parent) {
|
|
16
|
+
const meta = await parent.meta;
|
|
17
|
+
const slotDuration = await (0, time_travel_1.getSlotDuration)(parent.chain);
|
|
18
|
+
const currentTimestamp = await (0, time_travel_1.getCurrentTimestamp)(parent.chain);
|
|
19
|
+
return [new types_1.GenericExtrinsic(meta.registry, meta.tx.timestamp.set(currentTimestamp + slotDuration)).toHex()];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.SetTimestamp = SetTimestamp;
|
|
23
|
+
class InherentProviders {
|
|
24
|
+
#base;
|
|
25
|
+
#providers;
|
|
26
|
+
constructor(base, providers) {
|
|
27
|
+
this.#base = base;
|
|
28
|
+
this.#providers = providers;
|
|
29
|
+
}
|
|
30
|
+
async createInherents(parent, params) {
|
|
31
|
+
const base = await this.#base.createInherents(parent, params);
|
|
32
|
+
const extra = await Promise.all(this.#providers.map((provider) => provider.createInherents(parent, params)));
|
|
33
|
+
return [...base, ...extra.flat()];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.InherentProviders = InherentProviders;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { Block } from '../block';
|
|
3
|
+
import { BuildBlockParams } from '../txpool';
|
|
4
|
+
import { CreateInherents } from '.';
|
|
5
|
+
export declare class ParaInherentEnter implements CreateInherents {
|
|
6
|
+
createInherents(parent: Block, _params?: BuildBlockParams['inherent']): Promise<HexString[]>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ParaInherentEnter = void 0;
|
|
4
|
+
const types_1 = require("@polkadot/types");
|
|
5
|
+
class ParaInherentEnter {
|
|
6
|
+
async createInherents(parent, _params) {
|
|
7
|
+
const meta = await parent.meta;
|
|
8
|
+
if (!meta.tx.paraInherent?.enter) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
const extrinsics = await parent.extrinsics;
|
|
12
|
+
const paraEnterExtrinsic = extrinsics.find((extrinsic) => {
|
|
13
|
+
const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
|
|
14
|
+
return firstArg && 'bitfields' in firstArg;
|
|
15
|
+
});
|
|
16
|
+
if (!paraEnterExtrinsic) {
|
|
17
|
+
throw new Error('Missing paraInherent data from block');
|
|
18
|
+
}
|
|
19
|
+
const extrinsic = meta.registry
|
|
20
|
+
.createType('GenericExtrinsic', paraEnterExtrinsic)
|
|
21
|
+
.args[0].toJSON();
|
|
22
|
+
const parentHeader = (await parent.header).toJSON();
|
|
23
|
+
const newData = {
|
|
24
|
+
...extrinsic,
|
|
25
|
+
bitfields: [],
|
|
26
|
+
backedCandidates: [],
|
|
27
|
+
parentHeader,
|
|
28
|
+
};
|
|
29
|
+
// TODO: fill with data
|
|
30
|
+
return [new types_1.GenericExtrinsic(meta.registry, meta.tx.paraInherent.enter(newData)).toHex()];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.ParaInherentEnter = ParaInherentEnter;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { Block } from '../../../blockchain/block';
|
|
3
|
+
import { BuildBlockParams } from '../../txpool';
|
|
4
|
+
import { CreateInherents } from '..';
|
|
5
|
+
export declare class SetBabeRandomness implements CreateInherents {
|
|
6
|
+
createInherents(parent: Block, _params?: BuildBlockParams['inherent']): Promise<HexString[]>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SetBabeRandomness = void 0;
|
|
4
|
+
const types_1 = require("@polkadot/types");
|
|
5
|
+
// Support for Moonbeam pallet-randomness mandatory inherent
|
|
6
|
+
class SetBabeRandomness {
|
|
7
|
+
async createInherents(parent, _params) {
|
|
8
|
+
const meta = await parent.meta;
|
|
9
|
+
if (!meta.tx.randomness?.setBabeRandomnessResults) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return [new types_1.GenericExtrinsic(meta.registry, meta.tx.randomness.setBabeRandomnessResults()).toHex()];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.SetBabeRandomness = SetBabeRandomness;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { Block } from '../../../blockchain/block';
|
|
3
|
+
import { BuildBlockParams } from '../../txpool';
|
|
4
|
+
import { CreateInherents } from '..';
|
|
5
|
+
export declare class SetNimbusAuthorInherent implements CreateInherents {
|
|
6
|
+
createInherents(parent: Block, _params?: BuildBlockParams['inherent']): Promise<HexString[]>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SetNimbusAuthorInherent = void 0;
|
|
4
|
+
const types_1 = require("@polkadot/types");
|
|
5
|
+
// Support for Nimbus Author Inherent
|
|
6
|
+
class SetNimbusAuthorInherent {
|
|
7
|
+
async createInherents(parent, _params) {
|
|
8
|
+
const meta = await parent.meta;
|
|
9
|
+
if (!meta.tx.authorInherent?.kickOffAuthorshipValidation) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return [new types_1.GenericExtrinsic(meta.registry, meta.tx.authorInherent.kickOffAuthorshipValidation()).toHex()];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.SetNimbusAuthorInherent = SetNimbusAuthorInherent;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { Block } from '../../../blockchain/block';
|
|
3
|
+
import { BuildBlockParams } from '../../txpool';
|
|
4
|
+
import { CreateInherents } from '..';
|
|
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
|
+
}[]>;
|
|
14
|
+
validationData: {
|
|
15
|
+
relayParentNumber: number;
|
|
16
|
+
relayParentStorageRoot: HexString;
|
|
17
|
+
maxPovSize: number;
|
|
18
|
+
};
|
|
19
|
+
relayChainState: {
|
|
20
|
+
trieNodes: HexString[];
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export declare class SetValidationData implements CreateInherents {
|
|
24
|
+
createInherents(parent: Block, params?: BuildBlockParams['inherent']): Promise<HexString[]>;
|
|
25
|
+
}
|
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SetValidationData =
|
|
3
|
+
exports.SetValidationData = void 0;
|
|
4
4
|
const types_1 = require("@polkadot/types");
|
|
5
|
-
const utils_1 = require("../utils");
|
|
6
|
-
const executor_1 = require("../executor");
|
|
7
5
|
const util_1 = require("@polkadot/util");
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.#getTimestamp = getTimestamp;
|
|
13
|
-
}
|
|
14
|
-
async createInherents(meta, timestamp, _parent) {
|
|
15
|
-
return [new types_1.GenericExtrinsic(meta.registry, meta.tx.timestamp.set(timestamp)).toHex()];
|
|
16
|
-
}
|
|
17
|
-
getTimestamp(blockNumber) {
|
|
18
|
-
return this.#getTimestamp(blockNumber);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
exports.SetTimestamp = SetTimestamp;
|
|
6
|
+
const util_crypto_1 = require("@polkadot/util-crypto");
|
|
7
|
+
const utils_1 = require("../../../utils");
|
|
8
|
+
const executor_1 = require("../../../executor");
|
|
9
|
+
const proof_1 = require("../../../utils/proof");
|
|
22
10
|
const MOCK_VALIDATION_DATA = {
|
|
23
11
|
validationData: {
|
|
24
12
|
relayParentNumber: 1000,
|
|
@@ -43,35 +31,15 @@ const MOCK_VALIDATION_DATA = {
|
|
|
43
31
|
],
|
|
44
32
|
},
|
|
45
33
|
};
|
|
46
|
-
class InherentProviders {
|
|
47
|
-
#base;
|
|
48
|
-
#providers;
|
|
49
|
-
constructor(base, providers) {
|
|
50
|
-
this.#base = base;
|
|
51
|
-
this.#providers = providers;
|
|
52
|
-
}
|
|
53
|
-
async createInherents(meta, timestamp, parent) {
|
|
54
|
-
const base = await this.#base.createInherents(meta, timestamp, parent);
|
|
55
|
-
const extra = await Promise.all(this.#providers.map((provider) => provider.createInherents(meta, timestamp, parent)));
|
|
56
|
-
return [...base, ...extra.flat()];
|
|
57
|
-
}
|
|
58
|
-
getTimestamp(blockNumber) {
|
|
59
|
-
return this.#base.getTimestamp(blockNumber);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
exports.InherentProviders = InherentProviders;
|
|
63
34
|
class SetValidationData {
|
|
64
|
-
async createInherents(
|
|
35
|
+
async createInherents(parent, params) {
|
|
36
|
+
const meta = await parent.meta;
|
|
65
37
|
if (!meta.tx.parachainSystem?.setValidationData) {
|
|
66
38
|
return [];
|
|
67
39
|
}
|
|
68
|
-
const
|
|
69
|
-
if (!parentBlock) {
|
|
70
|
-
throw new Error('Parent block not found');
|
|
71
|
-
}
|
|
72
|
-
const extrinsics = await parentBlock.extrinsics;
|
|
40
|
+
const extrinsics = await parent.extrinsics;
|
|
73
41
|
let newData;
|
|
74
|
-
if (
|
|
42
|
+
if (parent.number === 0) {
|
|
75
43
|
// chain started with genesis, mock 1st validationData
|
|
76
44
|
newData = MOCK_VALIDATION_DATA;
|
|
77
45
|
}
|
|
@@ -87,17 +55,80 @@ class SetValidationData {
|
|
|
87
55
|
.createType('GenericExtrinsic', validationDataExtrinsic)
|
|
88
56
|
.args[0].toJSON();
|
|
89
57
|
const newEntries = [];
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
58
|
+
const downwardMessages = [];
|
|
59
|
+
const horizontalMessages = {};
|
|
60
|
+
const paraId = await (0, utils_1.getParaId)(parent.chain);
|
|
61
|
+
const dmqMqcHeadKey = (0, proof_1.dmqMqcHead)(paraId);
|
|
62
|
+
const hrmpIngressChannelIndexKey = (0, proof_1.hrmpIngressChannelIndex)(paraId);
|
|
63
|
+
const decoded = await (0, executor_1.decodeProof)(extrinsic.validationData.relayParentStorageRoot, [dmqMqcHeadKey, hrmpIngressChannelIndexKey], extrinsic.relayChainState.trieNodes);
|
|
64
|
+
// inject downward messages
|
|
65
|
+
if (params?.downwardMessages) {
|
|
66
|
+
let dmqMqcHeadHash = decoded[dmqMqcHeadKey];
|
|
67
|
+
if (!dmqMqcHeadHash)
|
|
68
|
+
throw new Error('Canoot find dmqMqcHead from validation data');
|
|
69
|
+
for (const { msg, sentAt } of params.downwardMessages) {
|
|
70
|
+
// calculate new hash
|
|
71
|
+
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);
|
|
72
|
+
downwardMessages.push({
|
|
73
|
+
msg,
|
|
74
|
+
sent_at: sentAt,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
newEntries.push([dmqMqcHeadKey, dmqMqcHeadHash]);
|
|
78
|
+
}
|
|
79
|
+
const hrmpIngressChannels = meta.registry
|
|
80
|
+
.createType('Vec<ParaId>', decoded[hrmpIngressChannelIndexKey])
|
|
81
|
+
.toJSON();
|
|
82
|
+
// inject horizontal messages
|
|
83
|
+
if (params?.horizontalMessages) {
|
|
84
|
+
for (const [id, messages] of Object.entries(params.horizontalMessages)) {
|
|
85
|
+
const sender = Number(id);
|
|
86
|
+
if (hrmpIngressChannels.includes(sender)) {
|
|
87
|
+
const channelId = meta.registry.createType('HrmpChannelId', {
|
|
88
|
+
sender,
|
|
89
|
+
receiver: paraId.toNumber(),
|
|
90
|
+
});
|
|
91
|
+
const hrmpChannelKey = (0, proof_1.hrmpChannels)(channelId);
|
|
92
|
+
const decoded = await (0, executor_1.decodeProof)(extrinsic.validationData.relayParentStorageRoot, [hrmpChannelKey], extrinsic.relayChainState.trieNodes);
|
|
93
|
+
const abridgedHrmpRaw = decoded[hrmpChannelKey];
|
|
94
|
+
if (!abridgedHrmpRaw)
|
|
95
|
+
throw new Error('Canoot find hrmp channels from validation data');
|
|
96
|
+
const abridgedHrmp = meta.registry
|
|
97
|
+
.createType('AbridgedHrmpChannel', (0, util_1.hexToU8a)(abridgedHrmpRaw))
|
|
98
|
+
.toJSON();
|
|
99
|
+
const paraMessages = [];
|
|
100
|
+
for (const { data, sentAt } of messages) {
|
|
101
|
+
// calculate new hash
|
|
102
|
+
const bytes = meta.registry.createType('Bytes', data);
|
|
103
|
+
abridgedHrmp.mqcHead = (0, util_crypto_1.blake2AsHex)((0, util_1.u8aConcat)(meta.registry.createType('Hash', abridgedHrmp.mqcHead).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), (0, util_crypto_1.blake2AsU8a)(bytes.toU8a(), 256)), 256);
|
|
104
|
+
abridgedHrmp.msgCount = abridgedHrmp.msgCount + 1;
|
|
105
|
+
abridgedHrmp.totalSize = abridgedHrmp.totalSize + bytes.length;
|
|
106
|
+
paraMessages.push({
|
|
107
|
+
data,
|
|
108
|
+
sent_at: sentAt,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
horizontalMessages[sender] = paraMessages;
|
|
112
|
+
newEntries.push([hrmpChannelKey, meta.registry.createType('AbridgedHrmpChannel', abridgedHrmp).toHex()]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const upgradeKey = (0, proof_1.upgradeGoAheadSignal)(paraId);
|
|
117
|
+
const pendingUpgrade = await parent.get((0, utils_1.compactHex)(meta.query.parachainSystem.pendingValidationCode()));
|
|
118
|
+
if (pendingUpgrade) {
|
|
119
|
+
// send goAhead signal
|
|
95
120
|
const goAhead = meta.registry.createType('UpgradeGoAhead', 'GoAhead');
|
|
96
121
|
newEntries.push([upgradeKey, goAhead.toHex()]);
|
|
97
122
|
}
|
|
123
|
+
else {
|
|
124
|
+
// make sure previous goAhead is removed
|
|
125
|
+
newEntries.push([upgradeKey, null]);
|
|
126
|
+
}
|
|
98
127
|
const { trieRootHash, nodes } = await (0, executor_1.createProof)(extrinsic.validationData.relayParentStorageRoot, extrinsic.relayChainState.trieNodes, newEntries);
|
|
99
128
|
newData = {
|
|
100
129
|
...extrinsic,
|
|
130
|
+
downwardMessages,
|
|
131
|
+
horizontalMessages,
|
|
101
132
|
validationData: {
|
|
102
133
|
...extrinsic.validationData,
|
|
103
134
|
relayParentStorageRoot: trieRootHash,
|
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import { HexString } from '@polkadot/util/types';
|
|
2
2
|
import { Blockchain } from '.';
|
|
3
|
-
import { InherentProvider } from './
|
|
3
|
+
import { InherentProvider } from './inherent';
|
|
4
4
|
export declare enum BuildBlockMode {
|
|
5
5
|
Batch = 0,
|
|
6
6
|
Instant = 1,
|
|
7
7
|
Manual = 2
|
|
8
8
|
}
|
|
9
|
+
export interface DownwardMessage {
|
|
10
|
+
sentAt: number;
|
|
11
|
+
msg: HexString;
|
|
12
|
+
}
|
|
13
|
+
export interface HorizontalMessage {
|
|
14
|
+
sentAt: number;
|
|
15
|
+
data: HexString;
|
|
16
|
+
}
|
|
17
|
+
export interface BuildBlockParams {
|
|
18
|
+
inherent?: {
|
|
19
|
+
downwardMessages?: DownwardMessage[];
|
|
20
|
+
horizontalMessages?: Record<number, HorizontalMessage[]>;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
9
23
|
export declare class TxPool {
|
|
10
24
|
#private;
|
|
11
25
|
constructor(chain: Blockchain, inherentProvider: InherentProvider, mode?: BuildBlockMode);
|
|
26
|
+
get pendingExtrinsics(): HexString[];
|
|
12
27
|
submitExtrinsic(extrinsic: HexString): void;
|
|
13
|
-
buildBlock(): Promise<void>;
|
|
28
|
+
buildBlock(params?: BuildBlockParams): Promise<void>;
|
|
14
29
|
}
|
|
@@ -4,26 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.TxPool = exports.BuildBlockMode = void 0;
|
|
7
|
-
const util_1 = require("@polkadot/util");
|
|
8
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
9
|
-
const
|
|
10
|
-
const shared_1 = require("../rpc/shared");
|
|
11
|
-
const utils_1 = require("../utils");
|
|
12
|
-
const logger_1 = require("../logger");
|
|
13
|
-
const logger = logger_1.defaultLogger.child({ name: 'txpool' });
|
|
8
|
+
const block_builder_1 = require("./block-builder");
|
|
14
9
|
var BuildBlockMode;
|
|
15
10
|
(function (BuildBlockMode) {
|
|
16
11
|
BuildBlockMode[BuildBlockMode["Batch"] = 0] = "Batch";
|
|
17
12
|
BuildBlockMode[BuildBlockMode["Instant"] = 1] = "Instant";
|
|
18
13
|
BuildBlockMode[BuildBlockMode["Manual"] = 2] = "Manual";
|
|
19
14
|
})(BuildBlockMode = exports.BuildBlockMode || (exports.BuildBlockMode = {}));
|
|
20
|
-
const getConsensus = (header) => {
|
|
21
|
-
if (header.digest.logs.length === 0)
|
|
22
|
-
return;
|
|
23
|
-
const preRuntime = header.digest.logs[0].asPreRuntime;
|
|
24
|
-
const [consensusEngine] = preRuntime;
|
|
25
|
-
return { consensusEngine, rest: header.digest.logs.slice(1) };
|
|
26
|
-
};
|
|
27
15
|
class TxPool {
|
|
28
16
|
#chain;
|
|
29
17
|
#pool = [];
|
|
@@ -35,6 +23,9 @@ class TxPool {
|
|
|
35
23
|
this.#mode = mode;
|
|
36
24
|
this.#inherentProvider = inherentProvider;
|
|
37
25
|
}
|
|
26
|
+
get pendingExtrinsics() {
|
|
27
|
+
return this.#pool;
|
|
28
|
+
}
|
|
38
29
|
submitExtrinsic(extrinsic) {
|
|
39
30
|
this.#pool.push(extrinsic);
|
|
40
31
|
switch (this.#mode) {
|
|
@@ -50,107 +41,20 @@ class TxPool {
|
|
|
50
41
|
}
|
|
51
42
|
}
|
|
52
43
|
#batchBuildBlock = lodash_1.default.debounce(this.buildBlock, 100, { maxWait: 1000 });
|
|
53
|
-
async buildBlock() {
|
|
44
|
+
async buildBlock(params) {
|
|
54
45
|
const last = this.#lastBuildBlockPromise;
|
|
55
|
-
this.#lastBuildBlockPromise = this.#buildBlock(last);
|
|
46
|
+
this.#lastBuildBlockPromise = this.#buildBlock(last, params);
|
|
56
47
|
await this.#lastBuildBlockPromise;
|
|
57
48
|
}
|
|
58
|
-
async #buildBlock(wait) {
|
|
49
|
+
async #buildBlock(wait, params) {
|
|
59
50
|
await this.#chain.api.isReady;
|
|
60
51
|
await wait.catch(() => { }); // ignore error
|
|
61
52
|
const head = this.#chain.head;
|
|
62
53
|
const extrinsics = this.#pool.splice(0);
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const expectedSlot = Math.floor(time / (meta.consts.timestamp.minimumPeriod.toNumber() * 2));
|
|
68
|
-
const consensus = getConsensus(parentHeader);
|
|
69
|
-
if (consensus?.consensusEngine.isAura) {
|
|
70
|
-
const newSlot = (0, util_1.compactAddLength)((0, util_1.bnToU8a)(expectedSlot, { isLe: true, bitLength: 64 }));
|
|
71
|
-
newLogs = [{ PreRuntime: [consensus.consensusEngine, newSlot] }, ...consensus.rest];
|
|
72
|
-
}
|
|
73
|
-
else if (consensus?.consensusEngine.isBabe) {
|
|
74
|
-
// trying to make a SecondaryPlainPreDigest
|
|
75
|
-
const newSlot = (0, util_1.compactAddLength)((0, util_1.u8aConcat)('0x0200000000', (0, util_1.bnToU8a)(expectedSlot, { isLe: true, bitLength: 64 })));
|
|
76
|
-
newLogs = [{ PreRuntime: [consensus.consensusEngine, newSlot] }, ...consensus.rest];
|
|
77
|
-
}
|
|
78
|
-
const registry = await head.registry;
|
|
79
|
-
const header = registry.createType('Header', {
|
|
80
|
-
parentHash: head.hash,
|
|
81
|
-
number: head.number + 1,
|
|
82
|
-
stateRoot: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
83
|
-
extrinsicsRoot: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
84
|
-
digest: {
|
|
85
|
-
logs: newLogs,
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
const newBlock = this.#chain.newTempBlock(head, header);
|
|
89
|
-
logger.info({
|
|
90
|
-
hash: head.hash,
|
|
91
|
-
number: head.number,
|
|
92
|
-
extrinsicsCount: extrinsics.length,
|
|
93
|
-
tempHash: newBlock.hash,
|
|
94
|
-
timeValue: time,
|
|
95
|
-
expectedSlot,
|
|
96
|
-
}, 'Building block');
|
|
97
|
-
const resp = await newBlock.call('Core_initialize_block', header.toHex());
|
|
98
|
-
logger.trace((0, logger_1.truncateStorageDiff)(resp.storageDiff), 'Initialize block');
|
|
99
|
-
newBlock.pushStorageLayer().setAll(resp.storageDiff);
|
|
100
|
-
if (meta.query.babe?.currentSlot) {
|
|
101
|
-
// TODO: figure out how to generate a valid babe slot digest instead of just modify the data
|
|
102
|
-
// but hey, we can get it working without a valid digest
|
|
103
|
-
const key = (0, utils_1.compactHex)(meta.query.babe.currentSlot());
|
|
104
|
-
newBlock.pushStorageLayer().set(key, (0, util_1.bnToHex)(expectedSlot, { isLe: true, bitLength: 64 }));
|
|
105
|
-
}
|
|
106
|
-
const inherents = await this.#inherentProvider.createInherents(meta, time, newBlock);
|
|
107
|
-
for (const extrinsic of inherents) {
|
|
108
|
-
try {
|
|
109
|
-
const resp = await newBlock.call('BlockBuilder_apply_extrinsic', extrinsic);
|
|
110
|
-
newBlock.pushStorageLayer().setAll(resp.storageDiff);
|
|
111
|
-
logger.trace((0, logger_1.truncateStorageDiff)(resp.storageDiff), 'Applied inherent');
|
|
112
|
-
}
|
|
113
|
-
catch (e) {
|
|
114
|
-
logger.warn('Failed to apply inherents %o %s', e, e);
|
|
115
|
-
throw new shared_1.ResponseError(1, 'Failed to apply inherents');
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
for (const extrinsic of extrinsics) {
|
|
119
|
-
try {
|
|
120
|
-
const resp = await newBlock.call('BlockBuilder_apply_extrinsic', extrinsic);
|
|
121
|
-
newBlock.pushStorageLayer().setAll(resp.storageDiff);
|
|
122
|
-
logger.trace((0, logger_1.truncateStorageDiff)(resp.storageDiff), 'Applied extrinsic');
|
|
123
|
-
}
|
|
124
|
-
catch (e) {
|
|
125
|
-
logger.info('Failed to apply extrinsic %o %s', e, e);
|
|
126
|
-
this.#pool.push(extrinsic);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (meta.query.paraInherent?.included) {
|
|
130
|
-
// TODO: remvoe this once paraInherent.enter is implemented
|
|
131
|
-
// we are relaychain, however as we have not yet implemented the paraInherent.enter
|
|
132
|
-
// so need to do some trick to make the on_finalize check happy
|
|
133
|
-
const paraInherentIncludedKey = (0, utils_1.compactHex)(meta.query.paraInherent.included());
|
|
134
|
-
newBlock.pushStorageLayer().set(paraInherentIncludedKey, '0x01');
|
|
135
|
-
}
|
|
136
|
-
const resp2 = await newBlock.call('BlockBuilder_finalize_block', '0x');
|
|
137
|
-
newBlock.pushStorageLayer().setAll(resp2.storageDiff);
|
|
138
|
-
logger.trace((0, logger_1.truncateStorageDiff)(resp2.storageDiff), 'Finalize block');
|
|
139
|
-
const blockData = registry.createType('Block', {
|
|
140
|
-
header,
|
|
141
|
-
extrinsics,
|
|
142
|
-
});
|
|
143
|
-
const finalBlock = new block_1.Block(this.#chain, newBlock.number, blockData.hash.toHex(), head, {
|
|
144
|
-
header,
|
|
145
|
-
extrinsics: [...inherents, ...extrinsics],
|
|
146
|
-
storage: head.storage,
|
|
147
|
-
});
|
|
148
|
-
const diff = await newBlock.storageDiff();
|
|
149
|
-
logger.trace(Object.entries(diff).map(([key, value]) => [key, (0, logger_1.truncate)(value)]), 'Final block');
|
|
150
|
-
finalBlock.pushStorageLayer().setAll(diff);
|
|
151
|
-
this.#chain.unregisterBlock(newBlock);
|
|
152
|
-
this.#chain.setHead(finalBlock);
|
|
153
|
-
logger.info({ hash: finalBlock.hash, number: finalBlock.number, prevHash: newBlock.hash }, 'Block built');
|
|
54
|
+
const inherents = await this.#inherentProvider.createInherents(head, params?.inherent);
|
|
55
|
+
const [newBlock, pendingExtrinsics] = await (0, block_builder_1.buildBlock)(head, inherents, extrinsics);
|
|
56
|
+
this.#pool.push(...pendingExtrinsics);
|
|
57
|
+
await this.#chain.setHead(newBlock);
|
|
154
58
|
}
|
|
155
59
|
}
|
|
156
60
|
exports.TxPool = TxPool;
|
package/dist/dry-run.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dryRun = void 0;
|
|
4
|
+
const util_crypto_1 = require("@polkadot/util-crypto");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const generate_html_diff_1 = require("./utils/generate-html-diff");
|
|
7
|
+
const open_html_1 = require("./utils/open-html");
|
|
8
|
+
const setup_1 = require("./setup");
|
|
9
|
+
const dryRun = async (argv) => {
|
|
10
|
+
const context = await (0, setup_1.setup)(argv);
|
|
11
|
+
const { outcome, storageDiff } = await context.chain.dryRunExtrinsic(argv['extrinsic']);
|
|
12
|
+
if (outcome.isErr) {
|
|
13
|
+
throw new Error(outcome.asErr.toString());
|
|
14
|
+
}
|
|
15
|
+
if (argv['html']) {
|
|
16
|
+
const filePath = await (0, generate_html_diff_1.generateHtmlDiffPreviewFile)(context.chain.head, storageDiff, (0, util_crypto_1.blake2AsHex)(argv['extrinsic'], 256));
|
|
17
|
+
console.log(`Generated preview ${filePath}`);
|
|
18
|
+
if (argv['open']) {
|
|
19
|
+
(0, open_html_1.openHtml)(filePath);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else if (argv['output-path']) {
|
|
23
|
+
(0, node_fs_1.writeFileSync)(argv['output-path'], JSON.stringify({ outcome: outcome.toHuman(), storageDiff }, null, 2));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
console.dir({ outcome: outcome.toHuman(), storageDiff }, { depth: null, colors: false });
|
|
27
|
+
}
|
|
28
|
+
process.exit(0);
|
|
29
|
+
};
|
|
30
|
+
exports.dryRun = dryRun;
|
package/dist/executor.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { HexString } from '@polkadot/util/types';
|
|
2
|
+
import { Block } from './blockchain/block';
|
|
3
|
+
import { Registry } from '@polkadot/types-codec/types';
|
|
4
|
+
interface JsCallback {
|
|
5
|
+
getStorage: (key: HexString) => Promise<string | undefined>;
|
|
6
|
+
getPrefixKeys: (key: HexString) => Promise<string[]>;
|
|
7
|
+
getNextKey: (key: HexString) => Promise<string | undefined>;
|
|
8
|
+
}
|
|
2
9
|
export type RuntimeVersion = {
|
|
3
10
|
specName: string;
|
|
4
11
|
implName: string;
|
|
@@ -12,15 +19,22 @@ export type RuntimeVersion = {
|
|
|
12
19
|
export declare const getRuntimeVersion: (code: HexString) => Promise<RuntimeVersion>;
|
|
13
20
|
export declare const calculateStateRoot: (entries: [HexString, HexString][]) => Promise<HexString>;
|
|
14
21
|
export declare const decodeProof: (trieRootHash: HexString, keys: HexString[], nodes: HexString[]) => Promise<Record<`0x${string}`, `0x${string}` | null>>;
|
|
15
|
-
export declare const createProof: (trieRootHash: HexString, nodes: HexString[], entries: [HexString, HexString][]) => Promise<{
|
|
22
|
+
export declare const createProof: (trieRootHash: HexString, nodes: HexString[], entries: [HexString, HexString | null][]) => Promise<{
|
|
16
23
|
trieRootHash: `0x${string}`;
|
|
17
24
|
nodes: `0x${string}`[];
|
|
18
25
|
}>;
|
|
19
26
|
export declare const runTask: (task: {
|
|
20
|
-
blockHash: HexString;
|
|
21
27
|
wasm: HexString;
|
|
22
28
|
calls: [string, HexString][];
|
|
23
29
|
storage: [HexString, HexString | null][];
|
|
24
30
|
mockSignatureHost: boolean;
|
|
25
31
|
allowUnresolvedImports: boolean;
|
|
26
|
-
}) => Promise<any>;
|
|
32
|
+
}, callback?: JsCallback) => Promise<any>;
|
|
33
|
+
export declare const taskHandler: (block: Block) => JsCallback;
|
|
34
|
+
export declare const emptyTaskHandler: {
|
|
35
|
+
getStorage: (_key: HexString) => Promise<never>;
|
|
36
|
+
getPrefixKeys: (_key: HexString) => Promise<never>;
|
|
37
|
+
getNextKey: (_key: HexString) => Promise<never>;
|
|
38
|
+
};
|
|
39
|
+
export declare const getAuraSlotDuration: ((wasm: HexString, registry: Registry) => Promise<number>) & import("lodash").MemoizedFunction;
|
|
40
|
+
export {};
|
package/dist/executor.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runTask = exports.createProof = exports.decodeProof = exports.calculateStateRoot = exports.getRuntimeVersion = void 0;
|
|
3
|
+
exports.getAuraSlotDuration = exports.emptyTaskHandler = exports.taskHandler = exports.runTask = exports.createProof = exports.decodeProof = exports.calculateStateRoot = exports.getRuntimeVersion = void 0;
|
|
4
4
|
const ws_1 = require("ws");
|
|
5
5
|
const util_1 = require("@polkadot/util");
|
|
6
6
|
global.WebSocket = ws_1.WebSocket;
|
|
7
7
|
const chopsticks_executor_1 = require("@acala-network/chopsticks-executor");
|
|
8
8
|
const logger_1 = require("./logger");
|
|
9
|
+
const lodash_1 = require("lodash");
|
|
9
10
|
const logger = logger_1.defaultLogger.child({ name: 'executor' });
|
|
10
11
|
const getRuntimeVersion = async (code) => {
|
|
11
12
|
return (0, chopsticks_executor_1.get_runtime_version)(code).then((version) => {
|
|
@@ -36,9 +37,9 @@ const createProof = async (trieRootHash, nodes, entries) => {
|
|
|
36
37
|
return { trieRootHash: result[0], nodes: result[1] };
|
|
37
38
|
};
|
|
38
39
|
exports.createProof = createProof;
|
|
39
|
-
const runTask = async (task) => {
|
|
40
|
+
const runTask = async (task, callback = exports.emptyTaskHandler) => {
|
|
40
41
|
logger.trace({ task: { ...task, wasm: (0, logger_1.truncate)(task.wasm) } }, 'taskRun');
|
|
41
|
-
const response = await (0, chopsticks_executor_1.run_task)(task);
|
|
42
|
+
const response = await (0, chopsticks_executor_1.run_task)(task, callback);
|
|
42
43
|
if (response.Call) {
|
|
43
44
|
logger.trace({ result: (0, logger_1.truncate)(response.Call.result), storageDiff: (0, logger_1.truncateStorageDiff)(response.Call.storageDiff) }, 'taskResponse');
|
|
44
45
|
}
|
|
@@ -48,3 +49,42 @@ const runTask = async (task) => {
|
|
|
48
49
|
return response;
|
|
49
50
|
};
|
|
50
51
|
exports.runTask = runTask;
|
|
52
|
+
const taskHandler = (block) => {
|
|
53
|
+
return {
|
|
54
|
+
getStorage: async function (key) {
|
|
55
|
+
return block.get(key);
|
|
56
|
+
},
|
|
57
|
+
getPrefixKeys: async function (key) {
|
|
58
|
+
return block.getKeysPaged({ prefix: key, pageSize: 1000, startKey: key });
|
|
59
|
+
},
|
|
60
|
+
getNextKey: async function (key) {
|
|
61
|
+
const keys = await block.getKeysPaged({ prefix: key, pageSize: 1, startKey: key });
|
|
62
|
+
return keys[0];
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
exports.taskHandler = taskHandler;
|
|
67
|
+
exports.emptyTaskHandler = {
|
|
68
|
+
getStorage: async function (_key) {
|
|
69
|
+
throw new Error('Method not implemented');
|
|
70
|
+
},
|
|
71
|
+
getPrefixKeys: async function (_key) {
|
|
72
|
+
throw new Error('Method not implemented');
|
|
73
|
+
},
|
|
74
|
+
getNextKey: async function (_key) {
|
|
75
|
+
throw new Error('Method not implemented');
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
exports.getAuraSlotDuration = (0, lodash_1.memoize)(async (wasm, registry) => {
|
|
79
|
+
const result = await (0, exports.runTask)({
|
|
80
|
+
wasm,
|
|
81
|
+
calls: [['AuraApi_slot_duration', '0x']],
|
|
82
|
+
storage: [],
|
|
83
|
+
mockSignatureHost: false,
|
|
84
|
+
allowUnresolvedImports: false,
|
|
85
|
+
});
|
|
86
|
+
if (!result.Call)
|
|
87
|
+
throw new Error(result.Error);
|
|
88
|
+
const slotDuration = registry.createType('u64', (0, util_1.hexToU8a)(result.Call.result)).toNumber();
|
|
89
|
+
return slotDuration;
|
|
90
|
+
});
|