@acala-network/chopsticks-core 1.2.7 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/blockchain/block-builder.js +8 -0
- package/dist/cjs/blockchain/inherent/parachain/validation-data.d.ts +2 -2
- package/dist/cjs/blockchain/inherent/parachain/validation-data.js +13 -34
- package/dist/cjs/setup.js +3 -0
- package/dist/cjs/xcm/upward.d.ts +4 -0
- package/dist/cjs/xcm/upward.js +25 -4
- package/dist/esm/blockchain/block-builder.js +9 -1
- package/dist/esm/blockchain/inherent/parachain/validation-data.d.ts +2 -2
- package/dist/esm/blockchain/inherent/parachain/validation-data.js +13 -34
- package/dist/esm/setup.js +3 -0
- package/dist/esm/xcm/upward.d.ts +4 -0
- package/dist/esm/xcm/upward.js +19 -1
- package/package.json +2 -2
|
@@ -151,6 +151,7 @@ const newHeader = async (head, unsafeBlockHeight)=>{
|
|
|
151
151
|
};
|
|
152
152
|
const initNewBlock = async (head, header, inherentProviders, params, storageLayer, callback)=>{
|
|
153
153
|
const blockNumber = header.number.toNumber();
|
|
154
|
+
const { unsafeBlockHeight } = params;
|
|
154
155
|
const hash = `0x${Math.round(Math.random() * 100000000).toString(16).padEnd(64, '0')}`;
|
|
155
156
|
const newBlock = new _block.Block(head.chain, blockNumber, hash, head, {
|
|
156
157
|
header,
|
|
@@ -158,6 +159,13 @@ const initNewBlock = async (head, header, inherentProviders, params, storageLaye
|
|
|
158
159
|
storage: storageLayer ?? head.storage
|
|
159
160
|
});
|
|
160
161
|
{
|
|
162
|
+
// override block number in storage when using unsafeBlockHeight
|
|
163
|
+
// this is needed because the runtime validates that block numbers are strictly increasing
|
|
164
|
+
if (unsafeBlockHeight !== undefined && blockNumber > head.number + 1) {
|
|
165
|
+
const meta = await head.meta;
|
|
166
|
+
const value = meta.registry.createType('BlockNumber', blockNumber - 1).toU8a();
|
|
167
|
+
newBlock.pushStorageLayer().set((0, _index.compactHex)(meta.query.system.number()), (0, _util.u8aToHex)(value));
|
|
168
|
+
}
|
|
161
169
|
// initialize block
|
|
162
170
|
const resp = await newBlock.call('Core_initialize_block', [
|
|
163
171
|
header.toHex()
|
|
@@ -3,8 +3,8 @@ import type { Block } from '../../block.js';
|
|
|
3
3
|
import type { BuildBlockParams, DownwardMessage, HorizontalMessage } from '../../txpool.js';
|
|
4
4
|
import type { InherentProvider } from '../index.js';
|
|
5
5
|
export type ValidationData = {
|
|
6
|
-
downwardMessages
|
|
7
|
-
horizontalMessages
|
|
6
|
+
downwardMessages?: DownwardMessage[];
|
|
7
|
+
horizontalMessages?: Record<number, HorizontalMessage[]>;
|
|
8
8
|
validationData: {
|
|
9
9
|
relayParentNumber: number;
|
|
10
10
|
relayParentStorageRoot: HexString;
|
|
@@ -51,8 +51,7 @@ const MOCK_VALIDATION_DATA = {
|
|
|
51
51
|
horizontalMessages: [],
|
|
52
52
|
downwardMessages: []
|
|
53
53
|
};
|
|
54
|
-
const getValidationData = async (parent
|
|
55
|
-
const meta = await parent.meta;
|
|
54
|
+
const getValidationData = async (parent)=>{
|
|
56
55
|
if (parent.number === 0) {
|
|
57
56
|
const { trieRootHash, nodes } = await (0, _index1.createProof)(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
|
|
58
57
|
return {
|
|
@@ -66,39 +65,19 @@ const getValidationData = async (parent, fallback = true)=>{
|
|
|
66
65
|
}
|
|
67
66
|
};
|
|
68
67
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
logger.warn('Failed to get validation data from block %d %s', parent.number, e);
|
|
81
|
-
if (fallback) {
|
|
82
|
-
// this could fail due to wasm override that breaks the validation data format
|
|
83
|
-
// so we will try parent's parent
|
|
84
|
-
const grandParent = await parent.parentBlock;
|
|
85
|
-
if (grandParent) {
|
|
86
|
-
const data = await getValidationData(grandParent, false);
|
|
87
|
-
return {
|
|
88
|
-
...data,
|
|
89
|
-
validationData: {
|
|
90
|
-
...data.validationData,
|
|
91
|
-
relayParentNumber: data.validationData.relayParentNumber + 2
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
} else {
|
|
95
|
-
throw e;
|
|
96
|
-
}
|
|
97
|
-
} else {
|
|
98
|
-
// fallback failed, throw error
|
|
99
|
-
throw e;
|
|
100
|
-
}
|
|
68
|
+
// Parent extrinsics are encoded by grand parent meta and new block extrinsics are encoded with parent meta.
|
|
69
|
+
const grandParent = await parent.parentBlock;
|
|
70
|
+
if (!grandParent) throw new Error('grand parent block not found');
|
|
71
|
+
const grandMeta = await grandParent.meta;
|
|
72
|
+
const extrinsics = await parent.extrinsics;
|
|
73
|
+
const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
|
|
74
|
+
const firstArg = grandMeta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
|
|
75
|
+
return firstArg && 'validationData' in firstArg;
|
|
76
|
+
});
|
|
77
|
+
if (!validationDataExtrinsic) {
|
|
78
|
+
throw new Error('Missing validation data from block');
|
|
101
79
|
}
|
|
80
|
+
return grandMeta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
|
|
102
81
|
};
|
|
103
82
|
class SetValidationData {
|
|
104
83
|
async createInherents(newBlock, params) {
|
package/dist/cjs/setup.js
CHANGED
|
@@ -26,10 +26,13 @@ const processOptions = async (options)=>{
|
|
|
26
26
|
_logger.defaultLogger.debug(options, 'Setup options');
|
|
27
27
|
let provider;
|
|
28
28
|
if (options.genesis) {
|
|
29
|
+
_logger.defaultLogger.debug(options, 'Setup options - genesis');
|
|
29
30
|
provider = options.genesis;
|
|
30
31
|
} else if (typeof options.endpoint === 'string' && /^(https|http):\/\//.test(options.endpoint || '')) {
|
|
32
|
+
_logger.defaultLogger.debug(options, 'Setup options - HTTP');
|
|
31
33
|
provider = new _rpcprovider.HttpProvider(options.endpoint);
|
|
32
34
|
} else {
|
|
35
|
+
_logger.defaultLogger.debug(options, 'Setup options - WS');
|
|
33
36
|
provider = new _rpcprovider.WsProvider(options.endpoint, 3_000, undefined, options.rpcTimeout);
|
|
34
37
|
}
|
|
35
38
|
const api = new _api.Api(provider);
|
package/dist/cjs/xcm/upward.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
import type { Blockchain } from '../blockchain/index.js';
|
|
2
|
+
/** Filter out UMP signals, keeping only XCM messages before the empty separator. */
|
|
3
|
+
export declare function filterXcmMessages<T extends {
|
|
4
|
+
length: number;
|
|
5
|
+
}>(messages: T[]): T[];
|
|
2
6
|
export declare const connectUpward: (parachain: Blockchain, relaychain: Blockchain) => Promise<void>;
|
package/dist/cjs/xcm/upward.js
CHANGED
|
@@ -2,14 +2,33 @@
|
|
|
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: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get connectUpward () {
|
|
8
13
|
return connectUpward;
|
|
14
|
+
},
|
|
15
|
+
get filterXcmMessages () {
|
|
16
|
+
return filterXcmMessages;
|
|
9
17
|
}
|
|
10
18
|
});
|
|
11
19
|
const _util = require("@polkadot/util");
|
|
12
20
|
const _index = require("../utils/index.js");
|
|
21
|
+
const _index1 = require("./index.js");
|
|
22
|
+
function filterXcmMessages(messages) {
|
|
23
|
+
const separatorIndex = messages.findIndex((m)=>m.length === 0);
|
|
24
|
+
if (separatorIndex === -1) return messages;
|
|
25
|
+
const signalCount = messages.length - separatorIndex - 1;
|
|
26
|
+
_index1.xcmLogger.debug({
|
|
27
|
+
xcmCount: separatorIndex,
|
|
28
|
+
signalCount
|
|
29
|
+
}, 'Filtered UMP signals from upward messages');
|
|
30
|
+
return messages.slice(0, separatorIndex);
|
|
31
|
+
}
|
|
13
32
|
const connectUpward = async (parachain, relaychain)=>{
|
|
14
33
|
const meta = await parachain.head.meta;
|
|
15
34
|
const paraId = (await (0, _index.getParaId)(parachain)).toNumber();
|
|
@@ -22,6 +41,8 @@ const connectUpward = async (parachain, relaychain)=>{
|
|
|
22
41
|
const meta = await relaychain.head.meta;
|
|
23
42
|
const upwardMessages = meta.registry.createType('Vec<Bytes>', (0, _util.hexToU8a)(value));
|
|
24
43
|
if (upwardMessages.length === 0) return;
|
|
25
|
-
|
|
44
|
+
const xcmMessages = filterXcmMessages(upwardMessages.toArray());
|
|
45
|
+
if (xcmMessages.length === 0) return;
|
|
46
|
+
relaychain.submitUpwardMessages(paraId, xcmMessages.map((x)=>x.toHex()));
|
|
26
47
|
});
|
|
27
48
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compactAddLength, hexToU8a, stringToHex, u8aConcat } from '@polkadot/util';
|
|
1
|
+
import { compactAddLength, hexToU8a, stringToHex, u8aConcat, u8aToHex } from '@polkadot/util';
|
|
2
2
|
import { blake2AsU8a } from '@polkadot/util-crypto';
|
|
3
3
|
import { defaultLogger, truncate } from '../logger.js';
|
|
4
4
|
import { compactHex, getCurrentSlot } from '../utils/index.js';
|
|
@@ -127,6 +127,7 @@ export const newHeader = async (head, unsafeBlockHeight)=>{
|
|
|
127
127
|
};
|
|
128
128
|
const initNewBlock = async (head, header, inherentProviders, params, storageLayer, callback)=>{
|
|
129
129
|
const blockNumber = header.number.toNumber();
|
|
130
|
+
const { unsafeBlockHeight } = params;
|
|
130
131
|
const hash = `0x${Math.round(Math.random() * 100000000).toString(16).padEnd(64, '0')}`;
|
|
131
132
|
const newBlock = new Block(head.chain, blockNumber, hash, head, {
|
|
132
133
|
header,
|
|
@@ -134,6 +135,13 @@ const initNewBlock = async (head, header, inherentProviders, params, storageLaye
|
|
|
134
135
|
storage: storageLayer ?? head.storage
|
|
135
136
|
});
|
|
136
137
|
{
|
|
138
|
+
// override block number in storage when using unsafeBlockHeight
|
|
139
|
+
// this is needed because the runtime validates that block numbers are strictly increasing
|
|
140
|
+
if (unsafeBlockHeight !== undefined && blockNumber > head.number + 1) {
|
|
141
|
+
const meta = await head.meta;
|
|
142
|
+
const value = meta.registry.createType('BlockNumber', blockNumber - 1).toU8a();
|
|
143
|
+
newBlock.pushStorageLayer().set(compactHex(meta.query.system.number()), u8aToHex(value));
|
|
144
|
+
}
|
|
137
145
|
// initialize block
|
|
138
146
|
const resp = await newBlock.call('Core_initialize_block', [
|
|
139
147
|
header.toHex()
|
|
@@ -3,8 +3,8 @@ import type { Block } from '../../block.js';
|
|
|
3
3
|
import type { BuildBlockParams, DownwardMessage, HorizontalMessage } from '../../txpool.js';
|
|
4
4
|
import type { InherentProvider } from '../index.js';
|
|
5
5
|
export type ValidationData = {
|
|
6
|
-
downwardMessages
|
|
7
|
-
horizontalMessages
|
|
6
|
+
downwardMessages?: DownwardMessage[];
|
|
7
|
+
horizontalMessages?: Record<number, HorizontalMessage[]>;
|
|
8
8
|
validationData: {
|
|
9
9
|
relayParentNumber: number;
|
|
10
10
|
relayParentStorageRoot: HexString;
|
|
@@ -36,8 +36,7 @@ const MOCK_VALIDATION_DATA = {
|
|
|
36
36
|
horizontalMessages: [],
|
|
37
37
|
downwardMessages: []
|
|
38
38
|
};
|
|
39
|
-
const getValidationData = async (parent
|
|
40
|
-
const meta = await parent.meta;
|
|
39
|
+
const getValidationData = async (parent)=>{
|
|
41
40
|
if (parent.number === 0) {
|
|
42
41
|
const { trieRootHash, nodes } = await createProof(MOCK_VALIDATION_DATA.relayChainState.trieNodes, []);
|
|
43
42
|
return {
|
|
@@ -51,39 +50,19 @@ const getValidationData = async (parent, fallback = true)=>{
|
|
|
51
50
|
}
|
|
52
51
|
};
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
logger.warn('Failed to get validation data from block %d %s', parent.number, e);
|
|
66
|
-
if (fallback) {
|
|
67
|
-
// this could fail due to wasm override that breaks the validation data format
|
|
68
|
-
// so we will try parent's parent
|
|
69
|
-
const grandParent = await parent.parentBlock;
|
|
70
|
-
if (grandParent) {
|
|
71
|
-
const data = await getValidationData(grandParent, false);
|
|
72
|
-
return {
|
|
73
|
-
...data,
|
|
74
|
-
validationData: {
|
|
75
|
-
...data.validationData,
|
|
76
|
-
relayParentNumber: data.validationData.relayParentNumber + 2
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
} else {
|
|
80
|
-
throw e;
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
// fallback failed, throw error
|
|
84
|
-
throw e;
|
|
85
|
-
}
|
|
53
|
+
// Parent extrinsics are encoded by grand parent meta and new block extrinsics are encoded with parent meta.
|
|
54
|
+
const grandParent = await parent.parentBlock;
|
|
55
|
+
if (!grandParent) throw new Error('grand parent block not found');
|
|
56
|
+
const grandMeta = await grandParent.meta;
|
|
57
|
+
const extrinsics = await parent.extrinsics;
|
|
58
|
+
const validationDataExtrinsic = extrinsics.find((extrinsic)=>{
|
|
59
|
+
const firstArg = grandMeta.registry.createType('GenericExtrinsic', extrinsic)?.args?.[0];
|
|
60
|
+
return firstArg && 'validationData' in firstArg;
|
|
61
|
+
});
|
|
62
|
+
if (!validationDataExtrinsic) {
|
|
63
|
+
throw new Error('Missing validation data from block');
|
|
86
64
|
}
|
|
65
|
+
return grandMeta.registry.createType('GenericExtrinsic', validationDataExtrinsic).args[0].toJSON();
|
|
87
66
|
};
|
|
88
67
|
export class SetValidationData {
|
|
89
68
|
async createInherents(newBlock, params) {
|
package/dist/esm/setup.js
CHANGED
|
@@ -8,10 +8,13 @@ export const processOptions = async (options)=>{
|
|
|
8
8
|
defaultLogger.debug(options, 'Setup options');
|
|
9
9
|
let provider;
|
|
10
10
|
if (options.genesis) {
|
|
11
|
+
defaultLogger.debug(options, 'Setup options - genesis');
|
|
11
12
|
provider = options.genesis;
|
|
12
13
|
} else if (typeof options.endpoint === 'string' && /^(https|http):\/\//.test(options.endpoint || '')) {
|
|
14
|
+
defaultLogger.debug(options, 'Setup options - HTTP');
|
|
13
15
|
provider = new HttpProvider(options.endpoint);
|
|
14
16
|
} else {
|
|
17
|
+
defaultLogger.debug(options, 'Setup options - WS');
|
|
15
18
|
provider = new WsProvider(options.endpoint, 3_000, undefined, options.rpcTimeout);
|
|
16
19
|
}
|
|
17
20
|
const api = new Api(provider);
|
package/dist/esm/xcm/upward.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
import type { Blockchain } from '../blockchain/index.js';
|
|
2
|
+
/** Filter out UMP signals, keeping only XCM messages before the empty separator. */
|
|
3
|
+
export declare function filterXcmMessages<T extends {
|
|
4
|
+
length: number;
|
|
5
|
+
}>(messages: T[]): T[];
|
|
2
6
|
export declare const connectUpward: (parachain: Blockchain, relaychain: Blockchain) => Promise<void>;
|
package/dist/esm/xcm/upward.js
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { hexToU8a } from '@polkadot/util';
|
|
2
2
|
import { compactHex, getParaId } from '../utils/index.js';
|
|
3
|
+
import { xcmLogger } from './index.js';
|
|
4
|
+
// The UpwardMessages storage contains both XCM messages and UMP signals (e.g. SelectCore,
|
|
5
|
+
// ApprovedPeer for elastic scaling), separated by an empty entry (UMP_SEPARATOR).
|
|
6
|
+
// Only messages before the separator are XCM; everything after is signals for the relay
|
|
7
|
+
// chain validators. This mirrors `skip_ump_signals` in the SDK's Polkadot primitives.
|
|
8
|
+
// See: [`polkadot-sdk/polkadot/primitives/src/v9/mod.rs`](https://github.com/paritytech/polkadot-sdk/blob/ff555bbd5b397e9984a42c34a799de8e5449f19f/polkadot/primitives/src/v9/mod.rs#L2771)
|
|
9
|
+
/** Filter out UMP signals, keeping only XCM messages before the empty separator. */ export function filterXcmMessages(messages) {
|
|
10
|
+
const separatorIndex = messages.findIndex((m)=>m.length === 0);
|
|
11
|
+
if (separatorIndex === -1) return messages;
|
|
12
|
+
const signalCount = messages.length - separatorIndex - 1;
|
|
13
|
+
xcmLogger.debug({
|
|
14
|
+
xcmCount: separatorIndex,
|
|
15
|
+
signalCount
|
|
16
|
+
}, 'Filtered UMP signals from upward messages');
|
|
17
|
+
return messages.slice(0, separatorIndex);
|
|
18
|
+
}
|
|
3
19
|
export const connectUpward = async (parachain, relaychain)=>{
|
|
4
20
|
const meta = await parachain.head.meta;
|
|
5
21
|
const paraId = (await getParaId(parachain)).toNumber();
|
|
@@ -12,6 +28,8 @@ export const connectUpward = async (parachain, relaychain)=>{
|
|
|
12
28
|
const meta = await relaychain.head.meta;
|
|
13
29
|
const upwardMessages = meta.registry.createType('Vec<Bytes>', hexToU8a(value));
|
|
14
30
|
if (upwardMessages.length === 0) return;
|
|
15
|
-
|
|
31
|
+
const xcmMessages = filterXcmMessages(upwardMessages.toArray());
|
|
32
|
+
if (xcmMessages.length === 0) return;
|
|
33
|
+
relaychain.submitUpwardMessages(paraId, xcmMessages.map((x)=>x.toHex()));
|
|
16
34
|
});
|
|
17
35
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acala-network/chopsticks-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"author": "Acala Developers <hello@acala.network>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"depcheck": "npx depcheck"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@acala-network/chopsticks-executor": "1.
|
|
17
|
+
"@acala-network/chopsticks-executor": "1.3.0",
|
|
18
18
|
"@polkadot/rpc-provider": "^16.4.1",
|
|
19
19
|
"@polkadot/types": "^16.4.1",
|
|
20
20
|
"@polkadot/types-codec": "^16.4.1",
|