diff --git a/packages/core/src/blockchain/inherent/parachain/validation-data.ts b/packages/core/src/blockchain/inherent/parachain/validation-data.ts index 9839906c..e81d5fc0 100644 --- a/packages/core/src/blockchain/inherent/parachain/validation-data.ts +++ b/packages/core/src/blockchain/inherent/parachain/validation-data.ts @@ -287,7 +287,7 @@ export class SetValidationData implements InherentProvider { validationData: { ...extrinsic.validationData, relayParentStorageRoot: trieRootHash, - relayParentNumber: extrinsic.validationData.relayParentNumber + relaySlotIncrease, + relayParentNumber: params.relayParentNumber ?? extrinsic.validationData.relayParentNumber + relaySlotIncrease, }, relayChainState: { trieNodes: nodes, diff --git a/packages/core/src/blockchain/txpool.ts b/packages/core/src/blockchain/txpool.ts index f12c807f..a313f7e2 100644 --- a/packages/core/src/blockchain/txpool.ts +++ b/packages/core/src/blockchain/txpool.ts @@ -40,6 +40,7 @@ export interface BuildBlockParams { transactions: HexString[] unsafeBlockHeight?: number relayChainStateOverrides?: [HexString, HexString | null][] + relayParentNumber?: number } export class TxPool { @@ -179,6 +180,7 @@ export class TxPool { const horizontalMessages = params?.horizontalMessages || { ...this.#hrmp } const unsafeBlockHeight = params?.unsafeBlockHeight const relayChainStateOverrides = params?.relayChainStateOverrides + const relayParentNumber = params?.relayParentNumber if (!params?.upwardMessages) { for (const id of Object.keys(this.#ump)) { delete this.#ump[id] @@ -198,6 +200,7 @@ export class TxPool { horizontalMessages, unsafeBlockHeight, relayChainStateOverrides, + relayParentNumber, }) // with the latest message queue, messages could be processed in the upcoming block diff --git a/packages/core/src/rpc/dev/new-block.ts b/packages/core/src/rpc/dev/new-block.ts index e7a09752..ef7f06b8 100644 --- a/packages/core/src/rpc/dev/new-block.ts +++ b/packages/core/src/rpc/dev/new-block.ts @@ -33,6 +33,7 @@ const schema = z.object({ transactions: z.array(zHex).min(1).optional(), unsafeBlockHeight: z.number().optional(), relayChainStateOverrides: z.array(z.tuple([zHex, z.union([zHex, z.null()])])).optional(), + relayParentNumber: z.number().optional(), }) type Params = z.infer @@ -70,6 +71,10 @@ export interface NewBlockParams { * Build block using a custom relay chain state */ relayChainStateOverrides: Params['relayChainStateOverrides'] + /** + * Build block using a custom relay parent number + */ + relayParentNumber: Params['relayParentNumber'] } /** @@ -111,9 +116,8 @@ export interface NewBlockParams { * ``` */ export const dev_newBlock = async (context: Context, [params]: [NewBlockParams]) => { - const { count, to, hrmp, ump, dmp, transactions, unsafeBlockHeight, relayChainStateOverrides } = schema.parse( - params || {}, - ) + const { count, to, hrmp, ump, dmp, transactions, unsafeBlockHeight, relayChainStateOverrides, relayParentNumber } = + schema.parse(params || {}) const now = context.chain.head.number const diff = to ? to - now : count const finalCount = diff !== undefined ? Math.max(diff, 1) : 1 @@ -132,6 +136,7 @@ export const dev_newBlock = async (context: Context, [params]: [NewBlockParams]) downwardMessages: dmp, unsafeBlockHeight: i === 0 ? unsafeBlockHeight : undefined, relayChainStateOverrides: relayChainStateOverrides, + relayParentNumber: relayParentNumber, }) .catch((error) => { throw new ResponseError(1, error.toString()) diff --git a/packages/e2e/src/build-parachain-block.test.ts b/packages/e2e/src/build-parachain-block.test.ts index a911a30a..7fa13681 100644 --- a/packages/e2e/src/build-parachain-block.test.ts +++ b/packages/e2e/src/build-parachain-block.test.ts @@ -30,4 +30,18 @@ describe('override-relay-state-proof', async () => { await teardown() }) + + it('newBlock with relayParentNumber', async () => { + const { dev, api, teardown } = await networks.acala() + + await dev.newBlock({ relayParentNumber: 14355209 }) + const block = await api.rpc.chain.getBlock() + const setValidationData = block.block.extrinsics + .find(({ method }) => method.method == 'setValidationData') + ?.method.toJSON().args.data + + expect(setValidationData.validationData.relayParentNumber).to.be.eq(14355209) + + await teardown() + }) }) diff --git a/packages/utils/package.json b/packages/utils/package.json index dc40bc36..e0a3bb8e 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@acala-network/chopsticks": "workspace:*", + "@acala-network/chopsticks-core": "workspace:*", "@polkadot/api": "^12.3.1", "@polkadot/api-base": "^12.3.1", "@polkadot/keyring": "^13.0.2", diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 0afb7ae3..16628bb1 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -13,6 +13,7 @@ import { Codec } from '@polkadot/types/types' import { Config } from '@acala-network/chopsticks/schema/index.js' import { HexString } from '@polkadot/util/types' import { Keyring, createTestKeyring } from '@polkadot/keyring' +import { NewBlockParams } from '@acala-network/chopsticks-core/rpc/dev/new-block.js' import { SubmittableExtrinsic } from '@polkadot/api-base/types' const logger = defaultLogger.child({ name: 'utils' }) @@ -96,7 +97,7 @@ export const setupContextWithConfig = async ({ timeout, ...config }: SetupConfig ws, api, dev: { - newBlock: (param?: { count?: number; to?: number; unsafeBlockHeight?: number }): Promise => { + newBlock: (param?: Partial): Promise => { return ws.send('dev_newBlock', [param]) }, setStorage: (values: StorageValues, blockHash?: string) => { diff --git a/yarn.lock b/yarn.lock index 99f088d2..008659d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,6 +93,7 @@ __metadata: resolution: "@acala-network/chopsticks-utils@workspace:packages/utils" dependencies: "@acala-network/chopsticks": "workspace:*" + "@acala-network/chopsticks-core": "workspace:*" "@polkadot/api": "npm:^12.3.1" "@polkadot/api-base": "npm:^12.3.1" "@polkadot/keyring": "npm:^13.0.2"