@acala-network/chopsticks-core 0.9.6-2 → 0.9.6-4
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/dist/cjs/blockchain/block-builder.js +12 -0
- package/dist/cjs/blockchain/inherent/para-enter.js +7 -0
- package/dist/cjs/blockchain/inherent/parachain/validation-data.js +157 -144
- package/dist/cjs/blockchain/txpool.js +13 -7
- package/dist/cjs/genesis-provider.d.ts +7 -4
- package/dist/cjs/genesis-provider.js +5 -3
- package/dist/cjs/setup.d.ts +1 -0
- package/dist/cjs/setup.js +57 -4
- package/dist/esm/blockchain/block-builder.js +12 -0
- package/dist/esm/blockchain/inherent/para-enter.js +7 -0
- package/dist/esm/blockchain/inherent/parachain/validation-data.js +158 -145
- package/dist/esm/blockchain/txpool.js +13 -7
- package/dist/esm/genesis-provider.d.ts +7 -4
- package/dist/esm/genesis-provider.js +5 -3
- package/dist/esm/setup.d.ts +1 -0
- package/dist/esm/setup.js +46 -1
- package/package.json +2 -2
|
@@ -141,6 +141,18 @@ const initNewBlock = async (head, header, inherents, storageLayer, callback)=>{
|
|
|
141
141
|
header.toHex()
|
|
142
142
|
]);
|
|
143
143
|
newBlock.pushStorageLayer().setAll(resp.storageDiff);
|
|
144
|
+
if (head.number === 0) {
|
|
145
|
+
// set parent hash for genesis block
|
|
146
|
+
// this makes sure to override the default parent hash
|
|
147
|
+
const meta = await head.meta;
|
|
148
|
+
const header = await head.header;
|
|
149
|
+
newBlock.pushStorageLayer().setAll([
|
|
150
|
+
[
|
|
151
|
+
(0, _index.compactHex)(meta.query.system.parentHash()),
|
|
152
|
+
header.hash.toHex()
|
|
153
|
+
]
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
144
156
|
callback?.onPhaseApplied?.('initialize', resp);
|
|
145
157
|
}
|
|
146
158
|
const layers = [];
|
|
@@ -15,6 +15,13 @@ class ParaInherentEnter {
|
|
|
15
15
|
if (!meta.tx.paraInherent?.enter) {
|
|
16
16
|
return [];
|
|
17
17
|
}
|
|
18
|
+
if (parent.number === 0) {
|
|
19
|
+
return [
|
|
20
|
+
new _types.GenericExtrinsic(meta.registry, meta.tx.paraInherent.enter({
|
|
21
|
+
parentHeader: (await parent.header).toJSON()
|
|
22
|
+
})).toHex()
|
|
23
|
+
];
|
|
24
|
+
}
|
|
18
25
|
const extrinsics = await parent.extrinsics;
|
|
19
26
|
const paraEnterExtrinsic = extrinsics.find((extrinsic)=>{
|
|
20
27
|
const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
|
|
@@ -23,7 +23,7 @@ function _interop_require_default(obj) {
|
|
|
23
23
|
const MOCK_VALIDATION_DATA = {
|
|
24
24
|
validationData: {
|
|
25
25
|
relayParentNumber: 1000,
|
|
26
|
-
relayParentStorageRoot: '
|
|
26
|
+
relayParentStorageRoot: '0x0',
|
|
27
27
|
maxPovSize: 5242880
|
|
28
28
|
},
|
|
29
29
|
relayChainState: {
|
|
@@ -42,7 +42,34 @@ const MOCK_VALIDATION_DATA = {
|
|
|
42
42
|
'0x9ede3d8a54d27e44a9d5ce189618f22d1008505f0e7b9012096b41c4eb3aaf947f6ea42908010080c74756edffa217dfb07ab596d82753deff985ac215e5cc2997d29afe1d397c16',
|
|
43
43
|
'0x9ef78c98723ddc9073523ef3beefda0c1004505f0e7b9012096b41c4eb3aaf947f6ea4290800007c77095dac46c07a40d91506e7637ec4ba5763f5a4efb16ffa83d00700000400'
|
|
44
44
|
]
|
|
45
|
+
},
|
|
46
|
+
horizontalMessages: [],
|
|
47
|
+
downwardMessages: []
|
|
48
|
+
};
|
|
49
|
+
const getValidationData = async (parent)=>{
|
|
50
|
+
const meta = await parent.meta;
|
|
51
|
+
if (parent.number === 0) {
|
|
52
|
+
const { trieRootHash, nodes } = await (0, _index1.createProof)(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
|
|
53
|
+
return {
|
|
54
|
+
...MOCK_VALIDATION_DATA,
|
|
55
|
+
relayChainState: {
|
|
56
|
+
trieNodes: nodes
|
|
57
|
+
},
|
|
58
|
+
validationData: {
|
|
59
|
+
...MOCK_VALIDATION_DATA.validationData,
|
|
60
|
+
relayParentStorageRoot: trieRootHash
|
|
61
|
+
}
|
|
62
|
+
};
|
|
45
63
|
}
|
|
64
|
+
const extrinsics = await parent.extrinsics;
|
|
65
|
+
const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
|
|
66
|
+
const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
|
|
67
|
+
return firstArg && 'validationData' in firstArg;
|
|
68
|
+
});
|
|
69
|
+
if (!validationDataExtrinsic) {
|
|
70
|
+
throw new Error('Missing validation data from block');
|
|
71
|
+
}
|
|
72
|
+
return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
|
|
46
73
|
};
|
|
47
74
|
class SetValidationData {
|
|
48
75
|
async createInherents(parent, params) {
|
|
@@ -50,158 +77,144 @@ class SetValidationData {
|
|
|
50
77
|
if (!meta.tx.parachainSystem?.setValidationData) {
|
|
51
78
|
return [];
|
|
52
79
|
}
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const newEntries = [];
|
|
68
|
-
const downwardMessages = [];
|
|
69
|
-
const horizontalMessages = {};
|
|
70
|
-
const paraId = await (0, _index.getParaId)(parent.chain);
|
|
71
|
-
const dmqMqcHeadKey = (0, _proof.dmqMqcHead)(paraId);
|
|
72
|
-
const hrmpIngressChannelIndexKey = (0, _proof.hrmpIngressChannelIndex)(paraId);
|
|
73
|
-
const hrmpEgressChannelIndexKey = (0, _proof.hrmpEgressChannelIndex)(paraId);
|
|
74
|
-
const decoded = await (0, _index1.decodeProof)(extrinsic.validationData.relayParentStorageRoot, extrinsic.relayChainState.trieNodes);
|
|
75
|
-
for (const key of Object.values(_proof.WELL_KNOWN_KEYS)){
|
|
76
|
-
if (key === _proof.WELL_KNOWN_KEYS.CURRENT_SLOT) {
|
|
77
|
-
// increment current slot
|
|
78
|
-
const currentSlot = meta.registry.createType('Slot', (0, _util.hexToU8a)(decoded[key])).toNumber();
|
|
79
|
-
const newSlot = meta.registry.createType('Slot', currentSlot + 2);
|
|
80
|
-
newEntries.push([
|
|
81
|
-
key,
|
|
82
|
-
(0, _util.u8aToHex)(newSlot.toU8a())
|
|
83
|
-
]);
|
|
84
|
-
} else {
|
|
85
|
-
newEntries.push([
|
|
86
|
-
key,
|
|
87
|
-
decoded[key]
|
|
88
|
-
]);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
newEntries.push([
|
|
92
|
-
hrmpIngressChannelIndexKey,
|
|
93
|
-
decoded[hrmpIngressChannelIndexKey]
|
|
94
|
-
]);
|
|
95
|
-
newEntries.push([
|
|
96
|
-
hrmpEgressChannelIndexKey,
|
|
97
|
-
decoded[hrmpEgressChannelIndexKey]
|
|
98
|
-
]);
|
|
99
|
-
// inject paraHead
|
|
100
|
-
const headData = meta.registry.createType('HeadData', (await parent.header).toHex());
|
|
101
|
-
newEntries.push([
|
|
102
|
-
(0, _proof.paraHead)(paraId),
|
|
103
|
-
(0, _util.u8aToHex)(headData.toU8a())
|
|
104
|
-
]);
|
|
105
|
-
// inject downward messages
|
|
106
|
-
let dmqMqcHeadHash = decoded[dmqMqcHeadKey];
|
|
107
|
-
if (dmqMqcHeadHash) {
|
|
108
|
-
for (const { msg, sentAt } of params.downwardMessages){
|
|
109
|
-
// calculate new hash
|
|
110
|
-
dmqMqcHeadHash = (0, _utilcrypto.blake2AsHex)((0, _util.u8aConcat)(meta.registry.createType('Hash', dmqMqcHeadHash).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), (0, _utilcrypto.blake2AsU8a)(meta.registry.createType('Bytes', msg).toU8a(), 256)), 256);
|
|
111
|
-
downwardMessages.push({
|
|
112
|
-
msg,
|
|
113
|
-
sentAt
|
|
114
|
-
});
|
|
115
|
-
}
|
|
80
|
+
const extrinsic = await getValidationData(parent);
|
|
81
|
+
const newEntries = [];
|
|
82
|
+
const downwardMessages = [];
|
|
83
|
+
const horizontalMessages = {};
|
|
84
|
+
const paraId = await (0, _index.getParaId)(parent.chain);
|
|
85
|
+
const dmqMqcHeadKey = (0, _proof.dmqMqcHead)(paraId);
|
|
86
|
+
const hrmpIngressChannelIndexKey = (0, _proof.hrmpIngressChannelIndex)(paraId);
|
|
87
|
+
const hrmpEgressChannelIndexKey = (0, _proof.hrmpEgressChannelIndex)(paraId);
|
|
88
|
+
const decoded = await (0, _index1.decodeProof)(extrinsic.validationData.relayParentStorageRoot, extrinsic.relayChainState.trieNodes);
|
|
89
|
+
for (const key of Object.values(_proof.WELL_KNOWN_KEYS)){
|
|
90
|
+
if (key === _proof.WELL_KNOWN_KEYS.CURRENT_SLOT) {
|
|
91
|
+
// increment current slot
|
|
92
|
+
const currentSlot = decoded[key] ? meta.registry.createType('Slot', (0, _util.hexToU8a)(decoded[key])).toNumber() : await (0, _index.getCurrentSlot)(parent.chain) * 2;
|
|
93
|
+
const newSlot = meta.registry.createType('Slot', currentSlot + 2);
|
|
116
94
|
newEntries.push([
|
|
117
|
-
|
|
118
|
-
|
|
95
|
+
key,
|
|
96
|
+
(0, _util.u8aToHex)(newSlot.toU8a())
|
|
119
97
|
]);
|
|
120
|
-
}
|
|
121
|
-
const hrmpIngressChannels = meta.registry.createType('Vec<ParaId>', decoded[hrmpIngressChannelIndexKey]).toJSON();
|
|
122
|
-
const hrmpEgressChannels = meta.registry.createType('Vec<ParaId>', decoded[hrmpEgressChannelIndexKey]).toJSON();
|
|
123
|
-
const hrmpMessages = {
|
|
124
|
-
// reset values, we just need the keys
|
|
125
|
-
..._lodash.default.mapValues(extrinsic.horizontalMessages, ()=>[]),
|
|
126
|
-
...params.horizontalMessages
|
|
127
|
-
};
|
|
128
|
-
// inject horizontal messages
|
|
129
|
-
for (const id of hrmpIngressChannels){
|
|
130
|
-
const messages = hrmpMessages[id];
|
|
131
|
-
const sender = Number(id);
|
|
132
|
-
const channelId = meta.registry.createType('HrmpChannelId', {
|
|
133
|
-
sender,
|
|
134
|
-
receiver: paraId.toNumber()
|
|
135
|
-
});
|
|
136
|
-
const hrmpChannelKey = (0, _proof.hrmpChannels)(channelId);
|
|
137
|
-
const abridgedHrmpRaw = decoded[hrmpChannelKey];
|
|
138
|
-
if (!abridgedHrmpRaw) throw new Error('Canoot find hrmp channels from validation data');
|
|
139
|
-
const abridgedHrmp = meta.registry.createType('AbridgedHrmpChannel', (0, _util.hexToU8a)(abridgedHrmpRaw)).toJSON();
|
|
140
|
-
const paraMessages = [];
|
|
141
|
-
for (const { data, sentAt: _unused } of messages){
|
|
142
|
-
// fake relaychain sentAt to make validationData think this msg was sent at previous block
|
|
143
|
-
const sentAt = extrinsic.validationData.relayParentNumber + 1;
|
|
144
|
-
// calculate new hash
|
|
145
|
-
const bytes = meta.registry.createType('Bytes', data);
|
|
146
|
-
abridgedHrmp.mqcHead = (0, _utilcrypto.blake2AsHex)((0, _util.u8aConcat)(meta.registry.createType('Hash', abridgedHrmp.mqcHead).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), (0, _utilcrypto.blake2AsU8a)(bytes.toU8a(), 256)), 256);
|
|
147
|
-
abridgedHrmp.msgCount = abridgedHrmp.msgCount + 1;
|
|
148
|
-
abridgedHrmp.totalSize = abridgedHrmp.totalSize + bytes.length;
|
|
149
|
-
paraMessages.push({
|
|
150
|
-
data,
|
|
151
|
-
sentAt
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
horizontalMessages[sender] = paraMessages;
|
|
98
|
+
} else {
|
|
155
99
|
newEntries.push([
|
|
156
|
-
|
|
157
|
-
|
|
100
|
+
key,
|
|
101
|
+
decoded[key]
|
|
158
102
|
]);
|
|
159
103
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
104
|
+
}
|
|
105
|
+
newEntries.push([
|
|
106
|
+
hrmpIngressChannelIndexKey,
|
|
107
|
+
decoded[hrmpIngressChannelIndexKey]
|
|
108
|
+
]);
|
|
109
|
+
newEntries.push([
|
|
110
|
+
hrmpEgressChannelIndexKey,
|
|
111
|
+
decoded[hrmpEgressChannelIndexKey]
|
|
112
|
+
]);
|
|
113
|
+
// inject paraHead
|
|
114
|
+
const headData = meta.registry.createType('HeadData', (await parent.header).toHex());
|
|
115
|
+
newEntries.push([
|
|
116
|
+
(0, _proof.paraHead)(paraId),
|
|
117
|
+
(0, _util.u8aToHex)(headData.toU8a())
|
|
118
|
+
]);
|
|
119
|
+
// inject downward messages
|
|
120
|
+
let dmqMqcHeadHash = decoded[dmqMqcHeadKey];
|
|
121
|
+
if (dmqMqcHeadHash) {
|
|
122
|
+
for (const { msg, sentAt } of params.downwardMessages){
|
|
123
|
+
// calculate new hash
|
|
124
|
+
dmqMqcHeadHash = (0, _utilcrypto.blake2AsHex)((0, _util.u8aConcat)(meta.registry.createType('Hash', dmqMqcHeadHash).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), (0, _utilcrypto.blake2AsU8a)(meta.registry.createType('Bytes', msg).toU8a(), 256)), 256);
|
|
125
|
+
downwardMessages.push({
|
|
126
|
+
msg,
|
|
127
|
+
sentAt
|
|
167
128
|
});
|
|
168
|
-
const hrmpChannelKey = (0, _proof.hrmpChannels)(channelId);
|
|
169
|
-
newEntries.push([
|
|
170
|
-
hrmpChannelKey,
|
|
171
|
-
decoded[hrmpChannelKey]
|
|
172
|
-
]);
|
|
173
129
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
130
|
+
newEntries.push([
|
|
131
|
+
dmqMqcHeadKey,
|
|
132
|
+
dmqMqcHeadHash
|
|
133
|
+
]);
|
|
134
|
+
}
|
|
135
|
+
const hrmpIngressChannels = meta.registry.createType('Vec<ParaId>', decoded[hrmpIngressChannelIndexKey]).toJSON();
|
|
136
|
+
const hrmpEgressChannels = meta.registry.createType('Vec<ParaId>', decoded[hrmpEgressChannelIndexKey]).toJSON();
|
|
137
|
+
const hrmpMessages = {
|
|
138
|
+
// reset values, we just need the keys
|
|
139
|
+
..._lodash.default.mapValues(extrinsic.horizontalMessages, ()=>[]),
|
|
140
|
+
...params.horizontalMessages
|
|
141
|
+
};
|
|
142
|
+
// inject horizontal messages
|
|
143
|
+
for (const id of hrmpIngressChannels){
|
|
144
|
+
const messages = hrmpMessages[id];
|
|
145
|
+
const sender = Number(id);
|
|
146
|
+
const channelId = meta.registry.createType('HrmpChannelId', {
|
|
147
|
+
sender,
|
|
148
|
+
receiver: paraId.toNumber()
|
|
149
|
+
});
|
|
150
|
+
const hrmpChannelKey = (0, _proof.hrmpChannels)(channelId);
|
|
151
|
+
const abridgedHrmpRaw = decoded[hrmpChannelKey];
|
|
152
|
+
if (!abridgedHrmpRaw) throw new Error('Canoot find hrmp channels from validation data');
|
|
153
|
+
const abridgedHrmp = meta.registry.createType('AbridgedHrmpChannel', (0, _util.hexToU8a)(abridgedHrmpRaw)).toJSON();
|
|
154
|
+
const paraMessages = [];
|
|
155
|
+
for (const { data, sentAt: _unused } of messages){
|
|
156
|
+
// fake relaychain sentAt to make validationData think this msg was sent at previous block
|
|
157
|
+
const sentAt = extrinsic.validationData.relayParentNumber + 1;
|
|
158
|
+
// calculate new hash
|
|
159
|
+
const bytes = meta.registry.createType('Bytes', data);
|
|
160
|
+
abridgedHrmp.mqcHead = (0, _utilcrypto.blake2AsHex)((0, _util.u8aConcat)(meta.registry.createType('Hash', abridgedHrmp.mqcHead).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), (0, _utilcrypto.blake2AsU8a)(bytes.toU8a(), 256)), 256);
|
|
161
|
+
abridgedHrmp.msgCount = abridgedHrmp.msgCount + 1;
|
|
162
|
+
abridgedHrmp.totalSize = abridgedHrmp.totalSize + bytes.length;
|
|
163
|
+
paraMessages.push({
|
|
164
|
+
data,
|
|
165
|
+
sentAt
|
|
166
|
+
});
|
|
189
167
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
validationData: {
|
|
196
|
-
...extrinsic.validationData,
|
|
197
|
-
relayParentStorageRoot: trieRootHash,
|
|
198
|
-
relayParentNumber: extrinsic.validationData.relayParentNumber + 2
|
|
199
|
-
},
|
|
200
|
-
relayChainState: {
|
|
201
|
-
trieNodes: nodes
|
|
202
|
-
}
|
|
203
|
-
};
|
|
168
|
+
horizontalMessages[sender] = paraMessages;
|
|
169
|
+
newEntries.push([
|
|
170
|
+
hrmpChannelKey,
|
|
171
|
+
meta.registry.createType('AbridgedHrmpChannel', abridgedHrmp).toHex()
|
|
172
|
+
]);
|
|
204
173
|
}
|
|
174
|
+
// inject hrmpEgressChannels proof
|
|
175
|
+
for (const id of hrmpEgressChannels){
|
|
176
|
+
// const messages = hrmpMessages[id]
|
|
177
|
+
const receiver = Number(id);
|
|
178
|
+
const channelId = meta.registry.createType('HrmpChannelId', {
|
|
179
|
+
sender: paraId.toNumber(),
|
|
180
|
+
receiver
|
|
181
|
+
});
|
|
182
|
+
const hrmpChannelKey = (0, _proof.hrmpChannels)(channelId);
|
|
183
|
+
newEntries.push([
|
|
184
|
+
hrmpChannelKey,
|
|
185
|
+
decoded[hrmpChannelKey]
|
|
186
|
+
]);
|
|
187
|
+
}
|
|
188
|
+
const upgradeKey = (0, _proof.upgradeGoAheadSignal)(paraId);
|
|
189
|
+
const pendingUpgrade = await parent.get((0, _index.compactHex)(meta.query.parachainSystem.pendingValidationCode()));
|
|
190
|
+
if (pendingUpgrade) {
|
|
191
|
+
// send goAhead signal
|
|
192
|
+
const goAhead = meta.registry.createType('UpgradeGoAhead', 'GoAhead');
|
|
193
|
+
newEntries.push([
|
|
194
|
+
upgradeKey,
|
|
195
|
+
goAhead.toHex()
|
|
196
|
+
]);
|
|
197
|
+
} else {
|
|
198
|
+
// make sure previous goAhead is removed
|
|
199
|
+
newEntries.push([
|
|
200
|
+
upgradeKey,
|
|
201
|
+
null
|
|
202
|
+
]);
|
|
203
|
+
}
|
|
204
|
+
const { trieRootHash, nodes } = await (0, _index1.createProof)(extrinsic.relayChainState.trieNodes, newEntries);
|
|
205
|
+
const newData = {
|
|
206
|
+
...extrinsic,
|
|
207
|
+
downwardMessages,
|
|
208
|
+
horizontalMessages,
|
|
209
|
+
validationData: {
|
|
210
|
+
...extrinsic.validationData,
|
|
211
|
+
relayParentStorageRoot: trieRootHash,
|
|
212
|
+
relayParentNumber: extrinsic.validationData.relayParentNumber + 2
|
|
213
|
+
},
|
|
214
|
+
relayChainState: {
|
|
215
|
+
trieNodes: nodes
|
|
216
|
+
}
|
|
217
|
+
};
|
|
205
218
|
const inherent = new _types.GenericExtrinsic(meta.registry, meta.tx.parachainSystem.setValidationData(newData));
|
|
206
219
|
return [
|
|
207
220
|
inherent.toHex()
|
|
@@ -202,13 +202,19 @@ class TxPool {
|
|
|
202
202
|
delete _class_private_field_get(this, _hrmp)[id];
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
205
|
+
try {
|
|
206
|
+
await this.buildBlockWithParams({
|
|
207
|
+
transactions,
|
|
208
|
+
upwardMessages,
|
|
209
|
+
downwardMessages,
|
|
210
|
+
horizontalMessages,
|
|
211
|
+
unsafeBlockHeight
|
|
212
|
+
});
|
|
213
|
+
} catch (err) {
|
|
214
|
+
logger.error({
|
|
215
|
+
err
|
|
216
|
+
}, 'build block failed');
|
|
217
|
+
}
|
|
212
218
|
}
|
|
213
219
|
async upcomingBlocks() {
|
|
214
220
|
const count = _class_private_field_get(this, _pendingBlocks).length;
|
|
@@ -7,6 +7,7 @@ import { JsCallback } from './wasm-executor/index.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export declare class GenesisProvider implements ProviderInterface {
|
|
9
9
|
#private;
|
|
10
|
+
genesisHeaderLogs: HexString[];
|
|
10
11
|
/**
|
|
11
12
|
* @ignore
|
|
12
13
|
* Create a genesis provider
|
|
@@ -25,21 +26,23 @@ export declare class GenesisProvider implements ProviderInterface {
|
|
|
25
26
|
on: (type: ProviderInterfaceEmitted, sub: ProviderInterfaceEmitCb) => (() => void);
|
|
26
27
|
get blockHash(): HexString;
|
|
27
28
|
getHeader: () => Promise<{
|
|
28
|
-
blockHash: `0x${string}`;
|
|
29
29
|
number: `0x${string}`;
|
|
30
30
|
stateRoot: `0x${string}`;
|
|
31
|
+
parentHash: string;
|
|
32
|
+
extrinsicsRoot: string;
|
|
31
33
|
digest: {
|
|
32
|
-
logs:
|
|
34
|
+
logs: `0x${string}`[];
|
|
33
35
|
};
|
|
34
36
|
}>;
|
|
35
37
|
getBlock: () => Promise<{
|
|
36
38
|
block: {
|
|
37
39
|
header: {
|
|
38
|
-
blockHash: `0x${string}`;
|
|
39
40
|
number: `0x${string}`;
|
|
40
41
|
stateRoot: `0x${string}`;
|
|
42
|
+
parentHash: string;
|
|
43
|
+
extrinsicsRoot: string;
|
|
41
44
|
digest: {
|
|
42
|
-
logs:
|
|
45
|
+
logs: `0x${string}`[];
|
|
43
46
|
};
|
|
44
47
|
};
|
|
45
48
|
extrinsics: never[];
|
|
@@ -79,7 +79,7 @@ class GenesisProvider {
|
|
|
79
79
|
return _class_private_field_get(this, _isReadyPromise);
|
|
80
80
|
}
|
|
81
81
|
get blockHash() {
|
|
82
|
-
return '
|
|
82
|
+
return '0x4545454545454545454545454545454545454545454545454545454545454545';
|
|
83
83
|
}
|
|
84
84
|
get _jsCallback() {
|
|
85
85
|
const storage = _class_private_field_get(this, _genesis).genesis.raw.top;
|
|
@@ -123,6 +123,7 @@ class GenesisProvider {
|
|
|
123
123
|
writable: true,
|
|
124
124
|
value: void 0
|
|
125
125
|
});
|
|
126
|
+
_define_property(this, "genesisHeaderLogs", []);
|
|
126
127
|
_define_property(this, "clone", ()=>{
|
|
127
128
|
return new GenesisProvider(_class_private_field_get(this, _genesis));
|
|
128
129
|
});
|
|
@@ -142,11 +143,12 @@ class GenesisProvider {
|
|
|
142
143
|
});
|
|
143
144
|
_define_property(this, "getHeader", async ()=>{
|
|
144
145
|
return {
|
|
145
|
-
blockHash: this.blockHash,
|
|
146
146
|
number: '0x0',
|
|
147
147
|
stateRoot: await _class_private_field_get(this, _stateRoot),
|
|
148
|
+
parentHash: '0x4545454545454545454545454545454545454545454545454545454545454545',
|
|
149
|
+
extrinsicsRoot: '0x03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
|
|
148
150
|
digest: {
|
|
149
|
-
logs:
|
|
151
|
+
logs: this.genesisHeaderLogs
|
|
150
152
|
}
|
|
151
153
|
};
|
|
152
154
|
});
|
package/dist/cjs/setup.d.ts
CHANGED
|
@@ -17,4 +17,5 @@ export type SetupOptions = {
|
|
|
17
17
|
offchainWorker?: boolean;
|
|
18
18
|
maxMemoryBlockCount?: number;
|
|
19
19
|
};
|
|
20
|
+
export declare const genesisSetup: (chain: Blockchain, genesis: GenesisProvider) => Promise<void>;
|
|
20
21
|
export declare const setup: (options: SetupOptions) => Promise<Blockchain>;
|
package/dist/cjs/setup.js
CHANGED
|
@@ -2,18 +2,67 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
genesisSetup: function() {
|
|
13
|
+
return genesisSetup;
|
|
14
|
+
},
|
|
15
|
+
setup: function() {
|
|
8
16
|
return setup;
|
|
9
17
|
}
|
|
10
18
|
});
|
|
11
19
|
require("@polkadot/types-codec");
|
|
12
20
|
const _rpcprovider = require("@polkadot/rpc-provider");
|
|
21
|
+
const _util = require("@polkadot/util");
|
|
13
22
|
const _api = require("./api.js");
|
|
14
23
|
const _index = require("./blockchain/index.js");
|
|
15
24
|
const _index1 = require("./blockchain/inherent/index.js");
|
|
16
25
|
const _logger = require("./logger.js");
|
|
26
|
+
const _index2 = require("./index.js");
|
|
27
|
+
const genesisSetup = async (chain, genesis)=>{
|
|
28
|
+
const meta = await chain.head.meta;
|
|
29
|
+
const timestamp = Date.now();
|
|
30
|
+
await (0, _index2.setStorage)(chain, {
|
|
31
|
+
Timestamp: {
|
|
32
|
+
Now: timestamp
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const slotDuration = await (0, _index2.getSlotDuration)(chain);
|
|
36
|
+
const currentSlot = Math.floor(timestamp / slotDuration);
|
|
37
|
+
if (meta.consts.babe) {
|
|
38
|
+
await (0, _index2.setStorage)(chain, {
|
|
39
|
+
Babe: {
|
|
40
|
+
CurrentSlot: currentSlot
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
genesis.genesisHeaderLogs = [
|
|
44
|
+
'0x0642414245b50103020200001c5fef100000000044cadd14aaefbda13ac8d85e1a6d58be082e7e2f56a4f95a3c612c784aaa4063f5517bf67d93ce633cde2fde7fbcf8ddca80017aaf8cd48436514687c662f60eda0ffa2c4781906416f4e71a196c9783c60c1b83d54c3a29365d03706714570b'
|
|
45
|
+
];
|
|
46
|
+
} else {
|
|
47
|
+
await (0, _index2.setStorage)(chain, {
|
|
48
|
+
Aura: {
|
|
49
|
+
CurrentSlot: currentSlot
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const newSlot = (0, _util.compactAddLength)(meta.registry.createType('Slot', currentSlot + 1).toU8a());
|
|
53
|
+
const consensusEngine = meta.registry.createType('ConsensusEngineId', 'aura');
|
|
54
|
+
const digest = meta.registry.createType('DigestItem', {
|
|
55
|
+
PreRuntime: [
|
|
56
|
+
consensusEngine,
|
|
57
|
+
newSlot
|
|
58
|
+
]
|
|
59
|
+
});
|
|
60
|
+
genesis.genesisHeaderLogs = [
|
|
61
|
+
digest.toHex()
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
await chain.newBlock();
|
|
65
|
+
};
|
|
17
66
|
const setup = async (options)=>{
|
|
18
67
|
_logger.defaultLogger.debug(options, 'Setup options');
|
|
19
68
|
let provider;
|
|
@@ -61,7 +110,7 @@ const setup = async (options)=>{
|
|
|
61
110
|
new _index1.SetNimbusAuthorInherent(),
|
|
62
111
|
new _index1.SetBabeRandomness()
|
|
63
112
|
]);
|
|
64
|
-
|
|
113
|
+
const chain = new _index.Blockchain({
|
|
65
114
|
api,
|
|
66
115
|
buildBlockMode: options.buildBlockMode,
|
|
67
116
|
inherentProvider: inherents,
|
|
@@ -77,4 +126,8 @@ const setup = async (options)=>{
|
|
|
77
126
|
offchainWorker: options.offchainWorker,
|
|
78
127
|
maxMemoryBlockCount: options.maxMemoryBlockCount
|
|
79
128
|
});
|
|
129
|
+
if (options.genesis) {
|
|
130
|
+
await genesisSetup(chain, options.genesis);
|
|
131
|
+
}
|
|
132
|
+
return chain;
|
|
80
133
|
};
|
|
@@ -117,6 +117,18 @@ const initNewBlock = async (head, header, inherents, storageLayer, callback)=>{
|
|
|
117
117
|
header.toHex()
|
|
118
118
|
]);
|
|
119
119
|
newBlock.pushStorageLayer().setAll(resp.storageDiff);
|
|
120
|
+
if (head.number === 0) {
|
|
121
|
+
// set parent hash for genesis block
|
|
122
|
+
// this makes sure to override the default parent hash
|
|
123
|
+
const meta = await head.meta;
|
|
124
|
+
const header = await head.header;
|
|
125
|
+
newBlock.pushStorageLayer().setAll([
|
|
126
|
+
[
|
|
127
|
+
compactHex(meta.query.system.parentHash()),
|
|
128
|
+
header.hash.toHex()
|
|
129
|
+
]
|
|
130
|
+
]);
|
|
131
|
+
}
|
|
120
132
|
callback?.onPhaseApplied?.('initialize', resp);
|
|
121
133
|
}
|
|
122
134
|
const layers = [];
|
|
@@ -5,6 +5,13 @@ export class ParaInherentEnter {
|
|
|
5
5
|
if (!meta.tx.paraInherent?.enter) {
|
|
6
6
|
return [];
|
|
7
7
|
}
|
|
8
|
+
if (parent.number === 0) {
|
|
9
|
+
return [
|
|
10
|
+
new GenericExtrinsic(meta.registry, meta.tx.paraInherent.enter({
|
|
11
|
+
parentHeader: (await parent.header).toJSON()
|
|
12
|
+
})).toHex()
|
|
13
|
+
];
|
|
14
|
+
}
|
|
8
15
|
const extrinsics = await parent.extrinsics;
|
|
9
16
|
const paraEnterExtrinsic = extrinsics.find((extrinsic)=>{
|
|
10
17
|
const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
|
|
@@ -3,12 +3,12 @@ import { hexToU8a, u8aConcat, u8aToHex } from '@polkadot/util';
|
|
|
3
3
|
import _ from 'lodash';
|
|
4
4
|
import { WELL_KNOWN_KEYS, dmqMqcHead, hrmpChannels, hrmpEgressChannelIndex, hrmpIngressChannelIndex, paraHead, upgradeGoAheadSignal } from '../../../utils/proof.js';
|
|
5
5
|
import { blake2AsHex, blake2AsU8a } from '@polkadot/util-crypto';
|
|
6
|
-
import { compactHex, getParaId } from '../../../utils/index.js';
|
|
6
|
+
import { compactHex, getCurrentSlot, getParaId } from '../../../utils/index.js';
|
|
7
7
|
import { createProof, decodeProof } from '../../../wasm-executor/index.js';
|
|
8
8
|
const MOCK_VALIDATION_DATA = {
|
|
9
9
|
validationData: {
|
|
10
10
|
relayParentNumber: 1000,
|
|
11
|
-
relayParentStorageRoot: '
|
|
11
|
+
relayParentStorageRoot: '0x0',
|
|
12
12
|
maxPovSize: 5242880
|
|
13
13
|
},
|
|
14
14
|
relayChainState: {
|
|
@@ -27,7 +27,34 @@ const MOCK_VALIDATION_DATA = {
|
|
|
27
27
|
'0x9ede3d8a54d27e44a9d5ce189618f22d1008505f0e7b9012096b41c4eb3aaf947f6ea42908010080c74756edffa217dfb07ab596d82753deff985ac215e5cc2997d29afe1d397c16',
|
|
28
28
|
'0x9ef78c98723ddc9073523ef3beefda0c1004505f0e7b9012096b41c4eb3aaf947f6ea4290800007c77095dac46c07a40d91506e7637ec4ba5763f5a4efb16ffa83d00700000400'
|
|
29
29
|
]
|
|
30
|
+
},
|
|
31
|
+
horizontalMessages: [],
|
|
32
|
+
downwardMessages: []
|
|
33
|
+
};
|
|
34
|
+
const getValidationData = async (parent)=>{
|
|
35
|
+
const meta = await parent.meta;
|
|
36
|
+
if (parent.number === 0) {
|
|
37
|
+
const { trieRootHash, nodes } = await createProof(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
|
|
38
|
+
return {
|
|
39
|
+
...MOCK_VALIDATION_DATA,
|
|
40
|
+
relayChainState: {
|
|
41
|
+
trieNodes: nodes
|
|
42
|
+
},
|
|
43
|
+
validationData: {
|
|
44
|
+
...MOCK_VALIDATION_DATA.validationData,
|
|
45
|
+
relayParentStorageRoot: trieRootHash
|
|
46
|
+
}
|
|
47
|
+
};
|
|
30
48
|
}
|
|
49
|
+
const extrinsics = await parent.extrinsics;
|
|
50
|
+
const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
|
|
51
|
+
const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
|
|
52
|
+
return firstArg && 'validationData' in firstArg;
|
|
53
|
+
});
|
|
54
|
+
if (!validationDataExtrinsic) {
|
|
55
|
+
throw new Error('Missing validation data from block');
|
|
56
|
+
}
|
|
57
|
+
return meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
|
|
31
58
|
};
|
|
32
59
|
export class SetValidationData {
|
|
33
60
|
async createInherents(parent, params) {
|
|
@@ -35,158 +62,144 @@ export class SetValidationData {
|
|
|
35
62
|
if (!meta.tx.parachainSystem?.setValidationData) {
|
|
36
63
|
return [];
|
|
37
64
|
}
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const newEntries = [];
|
|
53
|
-
const downwardMessages = [];
|
|
54
|
-
const horizontalMessages = {};
|
|
55
|
-
const paraId = await getParaId(parent.chain);
|
|
56
|
-
const dmqMqcHeadKey = dmqMqcHead(paraId);
|
|
57
|
-
const hrmpIngressChannelIndexKey = hrmpIngressChannelIndex(paraId);
|
|
58
|
-
const hrmpEgressChannelIndexKey = hrmpEgressChannelIndex(paraId);
|
|
59
|
-
const decoded = await decodeProof(extrinsic.validationData.relayParentStorageRoot, extrinsic.relayChainState.trieNodes);
|
|
60
|
-
for (const key of Object.values(WELL_KNOWN_KEYS)){
|
|
61
|
-
if (key === WELL_KNOWN_KEYS.CURRENT_SLOT) {
|
|
62
|
-
// increment current slot
|
|
63
|
-
const currentSlot = meta.registry.createType('Slot', hexToU8a(decoded[key])).toNumber();
|
|
64
|
-
const newSlot = meta.registry.createType('Slot', currentSlot + 2);
|
|
65
|
-
newEntries.push([
|
|
66
|
-
key,
|
|
67
|
-
u8aToHex(newSlot.toU8a())
|
|
68
|
-
]);
|
|
69
|
-
} else {
|
|
70
|
-
newEntries.push([
|
|
71
|
-
key,
|
|
72
|
-
decoded[key]
|
|
73
|
-
]);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
newEntries.push([
|
|
77
|
-
hrmpIngressChannelIndexKey,
|
|
78
|
-
decoded[hrmpIngressChannelIndexKey]
|
|
79
|
-
]);
|
|
80
|
-
newEntries.push([
|
|
81
|
-
hrmpEgressChannelIndexKey,
|
|
82
|
-
decoded[hrmpEgressChannelIndexKey]
|
|
83
|
-
]);
|
|
84
|
-
// inject paraHead
|
|
85
|
-
const headData = meta.registry.createType('HeadData', (await parent.header).toHex());
|
|
86
|
-
newEntries.push([
|
|
87
|
-
paraHead(paraId),
|
|
88
|
-
u8aToHex(headData.toU8a())
|
|
89
|
-
]);
|
|
90
|
-
// inject downward messages
|
|
91
|
-
let dmqMqcHeadHash = decoded[dmqMqcHeadKey];
|
|
92
|
-
if (dmqMqcHeadHash) {
|
|
93
|
-
for (const { msg, sentAt } of params.downwardMessages){
|
|
94
|
-
// calculate new hash
|
|
95
|
-
dmqMqcHeadHash = blake2AsHex(u8aConcat(meta.registry.createType('Hash', dmqMqcHeadHash).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), blake2AsU8a(meta.registry.createType('Bytes', msg).toU8a(), 256)), 256);
|
|
96
|
-
downwardMessages.push({
|
|
97
|
-
msg,
|
|
98
|
-
sentAt
|
|
99
|
-
});
|
|
100
|
-
}
|
|
65
|
+
const extrinsic = await getValidationData(parent);
|
|
66
|
+
const newEntries = [];
|
|
67
|
+
const downwardMessages = [];
|
|
68
|
+
const horizontalMessages = {};
|
|
69
|
+
const paraId = await getParaId(parent.chain);
|
|
70
|
+
const dmqMqcHeadKey = dmqMqcHead(paraId);
|
|
71
|
+
const hrmpIngressChannelIndexKey = hrmpIngressChannelIndex(paraId);
|
|
72
|
+
const hrmpEgressChannelIndexKey = hrmpEgressChannelIndex(paraId);
|
|
73
|
+
const decoded = await decodeProof(extrinsic.validationData.relayParentStorageRoot, extrinsic.relayChainState.trieNodes);
|
|
74
|
+
for (const key of Object.values(WELL_KNOWN_KEYS)){
|
|
75
|
+
if (key === WELL_KNOWN_KEYS.CURRENT_SLOT) {
|
|
76
|
+
// increment current slot
|
|
77
|
+
const currentSlot = decoded[key] ? meta.registry.createType('Slot', hexToU8a(decoded[key])).toNumber() : await getCurrentSlot(parent.chain) * 2;
|
|
78
|
+
const newSlot = meta.registry.createType('Slot', currentSlot + 2);
|
|
101
79
|
newEntries.push([
|
|
102
|
-
|
|
103
|
-
|
|
80
|
+
key,
|
|
81
|
+
u8aToHex(newSlot.toU8a())
|
|
104
82
|
]);
|
|
105
|
-
}
|
|
106
|
-
const hrmpIngressChannels = meta.registry.createType('Vec<ParaId>', decoded[hrmpIngressChannelIndexKey]).toJSON();
|
|
107
|
-
const hrmpEgressChannels = meta.registry.createType('Vec<ParaId>', decoded[hrmpEgressChannelIndexKey]).toJSON();
|
|
108
|
-
const hrmpMessages = {
|
|
109
|
-
// reset values, we just need the keys
|
|
110
|
-
..._.mapValues(extrinsic.horizontalMessages, ()=>[]),
|
|
111
|
-
...params.horizontalMessages
|
|
112
|
-
};
|
|
113
|
-
// inject horizontal messages
|
|
114
|
-
for (const id of hrmpIngressChannels){
|
|
115
|
-
const messages = hrmpMessages[id];
|
|
116
|
-
const sender = Number(id);
|
|
117
|
-
const channelId = meta.registry.createType('HrmpChannelId', {
|
|
118
|
-
sender,
|
|
119
|
-
receiver: paraId.toNumber()
|
|
120
|
-
});
|
|
121
|
-
const hrmpChannelKey = hrmpChannels(channelId);
|
|
122
|
-
const abridgedHrmpRaw = decoded[hrmpChannelKey];
|
|
123
|
-
if (!abridgedHrmpRaw) throw new Error('Canoot find hrmp channels from validation data');
|
|
124
|
-
const abridgedHrmp = meta.registry.createType('AbridgedHrmpChannel', hexToU8a(abridgedHrmpRaw)).toJSON();
|
|
125
|
-
const paraMessages = [];
|
|
126
|
-
for (const { data, sentAt: _unused } of messages){
|
|
127
|
-
// fake relaychain sentAt to make validationData think this msg was sent at previous block
|
|
128
|
-
const sentAt = extrinsic.validationData.relayParentNumber + 1;
|
|
129
|
-
// calculate new hash
|
|
130
|
-
const bytes = meta.registry.createType('Bytes', data);
|
|
131
|
-
abridgedHrmp.mqcHead = blake2AsHex(u8aConcat(meta.registry.createType('Hash', abridgedHrmp.mqcHead).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), blake2AsU8a(bytes.toU8a(), 256)), 256);
|
|
132
|
-
abridgedHrmp.msgCount = abridgedHrmp.msgCount + 1;
|
|
133
|
-
abridgedHrmp.totalSize = abridgedHrmp.totalSize + bytes.length;
|
|
134
|
-
paraMessages.push({
|
|
135
|
-
data,
|
|
136
|
-
sentAt
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
horizontalMessages[sender] = paraMessages;
|
|
83
|
+
} else {
|
|
140
84
|
newEntries.push([
|
|
141
|
-
|
|
142
|
-
|
|
85
|
+
key,
|
|
86
|
+
decoded[key]
|
|
143
87
|
]);
|
|
144
88
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
89
|
+
}
|
|
90
|
+
newEntries.push([
|
|
91
|
+
hrmpIngressChannelIndexKey,
|
|
92
|
+
decoded[hrmpIngressChannelIndexKey]
|
|
93
|
+
]);
|
|
94
|
+
newEntries.push([
|
|
95
|
+
hrmpEgressChannelIndexKey,
|
|
96
|
+
decoded[hrmpEgressChannelIndexKey]
|
|
97
|
+
]);
|
|
98
|
+
// inject paraHead
|
|
99
|
+
const headData = meta.registry.createType('HeadData', (await parent.header).toHex());
|
|
100
|
+
newEntries.push([
|
|
101
|
+
paraHead(paraId),
|
|
102
|
+
u8aToHex(headData.toU8a())
|
|
103
|
+
]);
|
|
104
|
+
// inject downward messages
|
|
105
|
+
let dmqMqcHeadHash = decoded[dmqMqcHeadKey];
|
|
106
|
+
if (dmqMqcHeadHash) {
|
|
107
|
+
for (const { msg, sentAt } of params.downwardMessages){
|
|
108
|
+
// calculate new hash
|
|
109
|
+
dmqMqcHeadHash = blake2AsHex(u8aConcat(meta.registry.createType('Hash', dmqMqcHeadHash).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), blake2AsU8a(meta.registry.createType('Bytes', msg).toU8a(), 256)), 256);
|
|
110
|
+
downwardMessages.push({
|
|
111
|
+
msg,
|
|
112
|
+
sentAt
|
|
152
113
|
});
|
|
153
|
-
const hrmpChannelKey = hrmpChannels(channelId);
|
|
154
|
-
newEntries.push([
|
|
155
|
-
hrmpChannelKey,
|
|
156
|
-
decoded[hrmpChannelKey]
|
|
157
|
-
]);
|
|
158
114
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
115
|
+
newEntries.push([
|
|
116
|
+
dmqMqcHeadKey,
|
|
117
|
+
dmqMqcHeadHash
|
|
118
|
+
]);
|
|
119
|
+
}
|
|
120
|
+
const hrmpIngressChannels = meta.registry.createType('Vec<ParaId>', decoded[hrmpIngressChannelIndexKey]).toJSON();
|
|
121
|
+
const hrmpEgressChannels = meta.registry.createType('Vec<ParaId>', decoded[hrmpEgressChannelIndexKey]).toJSON();
|
|
122
|
+
const hrmpMessages = {
|
|
123
|
+
// reset values, we just need the keys
|
|
124
|
+
..._.mapValues(extrinsic.horizontalMessages, ()=>[]),
|
|
125
|
+
...params.horizontalMessages
|
|
126
|
+
};
|
|
127
|
+
// inject horizontal messages
|
|
128
|
+
for (const id of hrmpIngressChannels){
|
|
129
|
+
const messages = hrmpMessages[id];
|
|
130
|
+
const sender = Number(id);
|
|
131
|
+
const channelId = meta.registry.createType('HrmpChannelId', {
|
|
132
|
+
sender,
|
|
133
|
+
receiver: paraId.toNumber()
|
|
134
|
+
});
|
|
135
|
+
const hrmpChannelKey = hrmpChannels(channelId);
|
|
136
|
+
const abridgedHrmpRaw = decoded[hrmpChannelKey];
|
|
137
|
+
if (!abridgedHrmpRaw) throw new Error('Canoot find hrmp channels from validation data');
|
|
138
|
+
const abridgedHrmp = meta.registry.createType('AbridgedHrmpChannel', hexToU8a(abridgedHrmpRaw)).toJSON();
|
|
139
|
+
const paraMessages = [];
|
|
140
|
+
for (const { data, sentAt: _unused } of messages){
|
|
141
|
+
// fake relaychain sentAt to make validationData think this msg was sent at previous block
|
|
142
|
+
const sentAt = extrinsic.validationData.relayParentNumber + 1;
|
|
143
|
+
// calculate new hash
|
|
144
|
+
const bytes = meta.registry.createType('Bytes', data);
|
|
145
|
+
abridgedHrmp.mqcHead = blake2AsHex(u8aConcat(meta.registry.createType('Hash', abridgedHrmp.mqcHead).toU8a(), meta.registry.createType('BlockNumber', sentAt).toU8a(), blake2AsU8a(bytes.toU8a(), 256)), 256);
|
|
146
|
+
abridgedHrmp.msgCount = abridgedHrmp.msgCount + 1;
|
|
147
|
+
abridgedHrmp.totalSize = abridgedHrmp.totalSize + bytes.length;
|
|
148
|
+
paraMessages.push({
|
|
149
|
+
data,
|
|
150
|
+
sentAt
|
|
151
|
+
});
|
|
174
152
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
validationData: {
|
|
181
|
-
...extrinsic.validationData,
|
|
182
|
-
relayParentStorageRoot: trieRootHash,
|
|
183
|
-
relayParentNumber: extrinsic.validationData.relayParentNumber + 2
|
|
184
|
-
},
|
|
185
|
-
relayChainState: {
|
|
186
|
-
trieNodes: nodes
|
|
187
|
-
}
|
|
188
|
-
};
|
|
153
|
+
horizontalMessages[sender] = paraMessages;
|
|
154
|
+
newEntries.push([
|
|
155
|
+
hrmpChannelKey,
|
|
156
|
+
meta.registry.createType('AbridgedHrmpChannel', abridgedHrmp).toHex()
|
|
157
|
+
]);
|
|
189
158
|
}
|
|
159
|
+
// inject hrmpEgressChannels proof
|
|
160
|
+
for (const id of hrmpEgressChannels){
|
|
161
|
+
// const messages = hrmpMessages[id]
|
|
162
|
+
const receiver = Number(id);
|
|
163
|
+
const channelId = meta.registry.createType('HrmpChannelId', {
|
|
164
|
+
sender: paraId.toNumber(),
|
|
165
|
+
receiver
|
|
166
|
+
});
|
|
167
|
+
const hrmpChannelKey = hrmpChannels(channelId);
|
|
168
|
+
newEntries.push([
|
|
169
|
+
hrmpChannelKey,
|
|
170
|
+
decoded[hrmpChannelKey]
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
173
|
+
const upgradeKey = upgradeGoAheadSignal(paraId);
|
|
174
|
+
const pendingUpgrade = await parent.get(compactHex(meta.query.parachainSystem.pendingValidationCode()));
|
|
175
|
+
if (pendingUpgrade) {
|
|
176
|
+
// send goAhead signal
|
|
177
|
+
const goAhead = meta.registry.createType('UpgradeGoAhead', 'GoAhead');
|
|
178
|
+
newEntries.push([
|
|
179
|
+
upgradeKey,
|
|
180
|
+
goAhead.toHex()
|
|
181
|
+
]);
|
|
182
|
+
} else {
|
|
183
|
+
// make sure previous goAhead is removed
|
|
184
|
+
newEntries.push([
|
|
185
|
+
upgradeKey,
|
|
186
|
+
null
|
|
187
|
+
]);
|
|
188
|
+
}
|
|
189
|
+
const { trieRootHash, nodes } = await createProof(extrinsic.relayChainState.trieNodes, newEntries);
|
|
190
|
+
const newData = {
|
|
191
|
+
...extrinsic,
|
|
192
|
+
downwardMessages,
|
|
193
|
+
horizontalMessages,
|
|
194
|
+
validationData: {
|
|
195
|
+
...extrinsic.validationData,
|
|
196
|
+
relayParentStorageRoot: trieRootHash,
|
|
197
|
+
relayParentNumber: extrinsic.validationData.relayParentNumber + 2
|
|
198
|
+
},
|
|
199
|
+
relayChainState: {
|
|
200
|
+
trieNodes: nodes
|
|
201
|
+
}
|
|
202
|
+
};
|
|
190
203
|
const inherent = new GenericExtrinsic(meta.registry, meta.tx.parachainSystem.setValidationData(newData));
|
|
191
204
|
return [
|
|
192
205
|
inherent.toHex()
|
|
@@ -147,13 +147,19 @@ export class TxPool {
|
|
|
147
147
|
delete this.#hrmp[id];
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
150
|
+
try {
|
|
151
|
+
await this.buildBlockWithParams({
|
|
152
|
+
transactions,
|
|
153
|
+
upwardMessages,
|
|
154
|
+
downwardMessages,
|
|
155
|
+
horizontalMessages,
|
|
156
|
+
unsafeBlockHeight
|
|
157
|
+
});
|
|
158
|
+
} catch (err) {
|
|
159
|
+
logger.error({
|
|
160
|
+
err
|
|
161
|
+
}, 'build block failed');
|
|
162
|
+
}
|
|
157
163
|
}
|
|
158
164
|
async upcomingBlocks() {
|
|
159
165
|
const count = this.#pendingBlocks.length;
|
|
@@ -7,6 +7,7 @@ import { JsCallback } from './wasm-executor/index.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export declare class GenesisProvider implements ProviderInterface {
|
|
9
9
|
#private;
|
|
10
|
+
genesisHeaderLogs: HexString[];
|
|
10
11
|
/**
|
|
11
12
|
* @ignore
|
|
12
13
|
* Create a genesis provider
|
|
@@ -25,21 +26,23 @@ export declare class GenesisProvider implements ProviderInterface {
|
|
|
25
26
|
on: (type: ProviderInterfaceEmitted, sub: ProviderInterfaceEmitCb) => (() => void);
|
|
26
27
|
get blockHash(): HexString;
|
|
27
28
|
getHeader: () => Promise<{
|
|
28
|
-
blockHash: `0x${string}`;
|
|
29
29
|
number: `0x${string}`;
|
|
30
30
|
stateRoot: `0x${string}`;
|
|
31
|
+
parentHash: string;
|
|
32
|
+
extrinsicsRoot: string;
|
|
31
33
|
digest: {
|
|
32
|
-
logs:
|
|
34
|
+
logs: `0x${string}`[];
|
|
33
35
|
};
|
|
34
36
|
}>;
|
|
35
37
|
getBlock: () => Promise<{
|
|
36
38
|
block: {
|
|
37
39
|
header: {
|
|
38
|
-
blockHash: `0x${string}`;
|
|
39
40
|
number: `0x${string}`;
|
|
40
41
|
stateRoot: `0x${string}`;
|
|
42
|
+
parentHash: string;
|
|
43
|
+
extrinsicsRoot: string;
|
|
41
44
|
digest: {
|
|
42
|
-
logs:
|
|
45
|
+
logs: `0x${string}`[];
|
|
43
46
|
};
|
|
44
47
|
};
|
|
45
48
|
extrinsics: never[];
|
|
@@ -9,6 +9,7 @@ import { calculateStateRoot, emptyTaskHandler } from './wasm-executor/index.js';
|
|
|
9
9
|
#isReadyPromise;
|
|
10
10
|
#genesis;
|
|
11
11
|
#stateRoot;
|
|
12
|
+
genesisHeaderLogs = [];
|
|
12
13
|
/**
|
|
13
14
|
* @ignore
|
|
14
15
|
* Create a genesis provider
|
|
@@ -59,15 +60,16 @@ import { calculateStateRoot, emptyTaskHandler } from './wasm-executor/index.js';
|
|
|
59
60
|
};
|
|
60
61
|
};
|
|
61
62
|
get blockHash() {
|
|
62
|
-
return '
|
|
63
|
+
return '0x4545454545454545454545454545454545454545454545454545454545454545';
|
|
63
64
|
}
|
|
64
65
|
getHeader = async ()=>{
|
|
65
66
|
return {
|
|
66
|
-
blockHash: this.blockHash,
|
|
67
67
|
number: '0x0',
|
|
68
68
|
stateRoot: await this.#stateRoot,
|
|
69
|
+
parentHash: '0x4545454545454545454545454545454545454545454545454545454545454545',
|
|
70
|
+
extrinsicsRoot: '0x03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314',
|
|
69
71
|
digest: {
|
|
70
|
-
logs:
|
|
72
|
+
logs: this.genesisHeaderLogs
|
|
71
73
|
}
|
|
72
74
|
};
|
|
73
75
|
};
|
package/dist/esm/setup.d.ts
CHANGED
|
@@ -17,4 +17,5 @@ export type SetupOptions = {
|
|
|
17
17
|
offchainWorker?: boolean;
|
|
18
18
|
maxMemoryBlockCount?: number;
|
|
19
19
|
};
|
|
20
|
+
export declare const genesisSetup: (chain: Blockchain, genesis: GenesisProvider) => Promise<void>;
|
|
20
21
|
export declare const setup: (options: SetupOptions) => Promise<Blockchain>;
|
package/dist/esm/setup.js
CHANGED
|
@@ -1,9 +1,50 @@
|
|
|
1
1
|
import '@polkadot/types-codec';
|
|
2
2
|
import { HttpProvider, WsProvider } from '@polkadot/rpc-provider';
|
|
3
|
+
import { compactAddLength } from '@polkadot/util';
|
|
3
4
|
import { Api } from './api.js';
|
|
4
5
|
import { Blockchain } from './blockchain/index.js';
|
|
5
6
|
import { InherentProviders, ParaInherentEnter, SetBabeRandomness, SetNimbusAuthorInherent, SetTimestamp, SetValidationData } from './blockchain/inherent/index.js';
|
|
6
7
|
import { defaultLogger } from './logger.js';
|
|
8
|
+
import { getSlotDuration, setStorage } from './index.js';
|
|
9
|
+
export const genesisSetup = async (chain, genesis)=>{
|
|
10
|
+
const meta = await chain.head.meta;
|
|
11
|
+
const timestamp = Date.now();
|
|
12
|
+
await setStorage(chain, {
|
|
13
|
+
Timestamp: {
|
|
14
|
+
Now: timestamp
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
const slotDuration = await getSlotDuration(chain);
|
|
18
|
+
const currentSlot = Math.floor(timestamp / slotDuration);
|
|
19
|
+
if (meta.consts.babe) {
|
|
20
|
+
await setStorage(chain, {
|
|
21
|
+
Babe: {
|
|
22
|
+
CurrentSlot: currentSlot
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
genesis.genesisHeaderLogs = [
|
|
26
|
+
'0x0642414245b50103020200001c5fef100000000044cadd14aaefbda13ac8d85e1a6d58be082e7e2f56a4f95a3c612c784aaa4063f5517bf67d93ce633cde2fde7fbcf8ddca80017aaf8cd48436514687c662f60eda0ffa2c4781906416f4e71a196c9783c60c1b83d54c3a29365d03706714570b'
|
|
27
|
+
];
|
|
28
|
+
} else {
|
|
29
|
+
await setStorage(chain, {
|
|
30
|
+
Aura: {
|
|
31
|
+
CurrentSlot: currentSlot
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const newSlot = compactAddLength(meta.registry.createType('Slot', currentSlot + 1).toU8a());
|
|
35
|
+
const consensusEngine = meta.registry.createType('ConsensusEngineId', 'aura');
|
|
36
|
+
const digest = meta.registry.createType('DigestItem', {
|
|
37
|
+
PreRuntime: [
|
|
38
|
+
consensusEngine,
|
|
39
|
+
newSlot
|
|
40
|
+
]
|
|
41
|
+
});
|
|
42
|
+
genesis.genesisHeaderLogs = [
|
|
43
|
+
digest.toHex()
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
await chain.newBlock();
|
|
47
|
+
};
|
|
7
48
|
export const setup = async (options)=>{
|
|
8
49
|
defaultLogger.debug(options, 'Setup options');
|
|
9
50
|
let provider;
|
|
@@ -51,7 +92,7 @@ export const setup = async (options)=>{
|
|
|
51
92
|
new SetNimbusAuthorInherent(),
|
|
52
93
|
new SetBabeRandomness()
|
|
53
94
|
]);
|
|
54
|
-
|
|
95
|
+
const chain = new Blockchain({
|
|
55
96
|
api,
|
|
56
97
|
buildBlockMode: options.buildBlockMode,
|
|
57
98
|
inherentProvider: inherents,
|
|
@@ -67,4 +108,8 @@ export const setup = async (options)=>{
|
|
|
67
108
|
offchainWorker: options.offchainWorker,
|
|
68
109
|
maxMemoryBlockCount: options.maxMemoryBlockCount
|
|
69
110
|
});
|
|
111
|
+
if (options.genesis) {
|
|
112
|
+
await genesisSetup(chain, options.genesis);
|
|
113
|
+
}
|
|
114
|
+
return chain;
|
|
70
115
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acala-network/chopsticks-core",
|
|
3
|
-
"version": "0.9.6-
|
|
3
|
+
"version": "0.9.6-4",
|
|
4
4
|
"author": "Acala Developers <hello@acala.network>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"docs:prep": "typedoc"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@acala-network/chopsticks-executor": "0.9.6-
|
|
15
|
+
"@acala-network/chopsticks-executor": "0.9.6-4",
|
|
16
16
|
"@polkadot/rpc-provider": "^10.10.1",
|
|
17
17
|
"@polkadot/types": "^10.10.1",
|
|
18
18
|
"@polkadot/types-codec": "^10.10.1",
|