@acala-network/chopsticks-core 0.9.6-2 → 0.9.6-3

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.
@@ -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: '0x49416764844ff0d8bad851e8abe686dff9dd2de78621180ef8e9f99bb7a480f1',
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 extrinsics = await parent.extrinsics;
54
- let newData;
55
- if (parent.number === 0) {
56
- // chain started with genesis, mock 1st validationData
57
- newData = MOCK_VALIDATION_DATA;
58
- } else {
59
- const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
60
- const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
61
- return firstArg && 'validationData' in firstArg;
62
- });
63
- if (!validationDataExtrinsic) {
64
- throw new Error('Missing validation data from block');
65
- }
66
- const extrinsic = meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
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
- dmqMqcHeadKey,
118
- dmqMqcHeadHash
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
- hrmpChannelKey,
157
- meta.registry.createType('AbridgedHrmpChannel', abridgedHrmp).toHex()
100
+ key,
101
+ decoded[key]
158
102
  ]);
159
103
  }
160
- // inject hrmpEgressChannels proof
161
- for (const id of hrmpEgressChannels){
162
- // const messages = hrmpMessages[id]
163
- const receiver = Number(id);
164
- const channelId = meta.registry.createType('HrmpChannelId', {
165
- sender: paraId.toNumber(),
166
- receiver
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
- const upgradeKey = (0, _proof.upgradeGoAheadSignal)(paraId);
175
- const pendingUpgrade = await parent.get((0, _index.compactHex)(meta.query.parachainSystem.pendingValidationCode()));
176
- if (pendingUpgrade) {
177
- // send goAhead signal
178
- const goAhead = meta.registry.createType('UpgradeGoAhead', 'GoAhead');
179
- newEntries.push([
180
- upgradeKey,
181
- goAhead.toHex()
182
- ]);
183
- } else {
184
- // make sure previous goAhead is removed
185
- newEntries.push([
186
- upgradeKey,
187
- null
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
- const { trieRootHash, nodes } = await (0, _index1.createProof)(extrinsic.relayChainState.trieNodes, newEntries);
191
- newData = {
192
- ...extrinsic,
193
- downwardMessages,
194
- horizontalMessages,
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
- await this.buildBlockWithParams({
206
- transactions,
207
- upwardMessages,
208
- downwardMessages,
209
- horizontalMessages,
210
- unsafeBlockHeight
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: never[];
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: never[];
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 '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
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
  });
@@ -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
- Object.defineProperty(exports, "setup", {
6
- enumerable: true,
7
- get: function() {
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
- return new _index.Blockchain({
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: '0x49416764844ff0d8bad851e8abe686dff9dd2de78621180ef8e9f99bb7a480f1',
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 extrinsics = await parent.extrinsics;
39
- let newData;
40
- if (parent.number === 0) {
41
- // chain started with genesis, mock 1st validationData
42
- newData = MOCK_VALIDATION_DATA;
43
- } else {
44
- const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
45
- const firstArg = meta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
46
- return firstArg && 'validationData' in firstArg;
47
- });
48
- if (!validationDataExtrinsic) {
49
- throw new Error('Missing validation data from block');
50
- }
51
- const extrinsic = meta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
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
- dmqMqcHeadKey,
103
- dmqMqcHeadHash
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
- hrmpChannelKey,
142
- meta.registry.createType('AbridgedHrmpChannel', abridgedHrmp).toHex()
85
+ key,
86
+ decoded[key]
143
87
  ]);
144
88
  }
145
- // inject hrmpEgressChannels proof
146
- for (const id of hrmpEgressChannels){
147
- // const messages = hrmpMessages[id]
148
- const receiver = Number(id);
149
- const channelId = meta.registry.createType('HrmpChannelId', {
150
- sender: paraId.toNumber(),
151
- receiver
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
- const upgradeKey = upgradeGoAheadSignal(paraId);
160
- const pendingUpgrade = await parent.get(compactHex(meta.query.parachainSystem.pendingValidationCode()));
161
- if (pendingUpgrade) {
162
- // send goAhead signal
163
- const goAhead = meta.registry.createType('UpgradeGoAhead', 'GoAhead');
164
- newEntries.push([
165
- upgradeKey,
166
- goAhead.toHex()
167
- ]);
168
- } else {
169
- // make sure previous goAhead is removed
170
- newEntries.push([
171
- upgradeKey,
172
- null
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
- const { trieRootHash, nodes } = await createProof(extrinsic.relayChainState.trieNodes, newEntries);
176
- newData = {
177
- ...extrinsic,
178
- downwardMessages,
179
- horizontalMessages,
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
- await this.buildBlockWithParams({
151
- transactions,
152
- upwardMessages,
153
- downwardMessages,
154
- horizontalMessages,
155
- unsafeBlockHeight
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: never[];
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: never[];
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 '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3';
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
  };
@@ -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
- return new Blockchain({
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-2",
3
+ "version": "0.9.6-3",
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-2",
15
+ "@acala-network/chopsticks-executor": "0.9.6-3",
16
16
  "@polkadot/rpc-provider": "^10.10.1",
17
17
  "@polkadot/types": "^10.10.1",
18
18
  "@polkadot/types-codec": "^10.10.1",