diff --git a/solo-chains/node/tanssi-relay-service/src/dev_rpcs.rs b/solo-chains/node/tanssi-relay-service/src/dev_rpcs.rs index 5ccd24e5a..32eb11dbe 100644 --- a/solo-chains/node/tanssi-relay-service/src/dev_rpcs.rs +++ b/solo-chains/node/tanssi-relay-service/src/dev_rpcs.rs @@ -47,6 +47,7 @@ pub struct DevRpc { #[jsonrpsee::core::async_trait] impl DevApiServer for DevRpc { async fn enable_para_inherent_candidate(&self) -> RpcResult<()> { + log::info!("entering here"); let mock_para_inherent_channel = self.mock_para_inherent_channel.clone(); // Push the message to the shared channel where it will be queued up // to be injected in to an upcoming block. @@ -55,6 +56,7 @@ impl DevApiServer for DevRpc { .await .map_err(|err| internal_err(err.to_string()))?; + log::info!("SENEDING ENABLE"); Ok(()) } diff --git a/solo-chains/node/tanssi-relay-service/src/dev_service.rs b/solo-chains/node/tanssi-relay-service/src/dev_service.rs index c2dc8ac26..a76fa5eb5 100644 --- a/solo-chains/node/tanssi-relay-service/src/dev_service.rs +++ b/solo-chains/node/tanssi-relay-service/src/dev_service.rs @@ -279,10 +279,7 @@ where Err(err) => return Err(InherentError::Blockchain(err)), }; - let parent_hash = client - .hash(parent_header_relay.number.saturating_sub(1)) - .unwrap() - .unwrap(); + let parent_hash = parent; let parent_header = match client.header(parent_hash) { Ok(Some(h)) => h, @@ -364,7 +361,7 @@ where polkadot_primitives::ValidatorId::from_slice(&type_public_pair) { if validator_keys_to_find == &validator { - let persisted_validation_data = runtime_api + let mut persisted_validation_data = runtime_api .persisted_validation_data( parent_hash, para[0], @@ -373,6 +370,9 @@ where .unwrap() .unwrap(); + // if we dont do this we have a backed candidate every 2 blocks + persisted_validation_data.relay_parent_storage_root = parent_header.state_root; + let persisted_validation_data_hash = persisted_validation_data.hash(); let validation_code_hash = runtime_api .validation_code_hash( @@ -431,8 +431,6 @@ where .unwrap() .benchmark_signature(); - log::info!("after sig"); - let validity_votes = vec![ValidityAttestation::Explicit(signature)]; backed_cand.push(BackedCandidate::::new( diff --git a/test/suites/dev-tanssi-relay/paras-candidate-inherent/test_paras_candidate_inherent.ts b/test/suites/dev-tanssi-relay/paras-candidate-inherent/test_paras_candidate_inherent.ts new file mode 100644 index 000000000..ccbb1fb92 --- /dev/null +++ b/test/suites/dev-tanssi-relay/paras-candidate-inherent/test_paras_candidate_inherent.ts @@ -0,0 +1,45 @@ +import "@tanssi/api-augment"; +import { describeSuite, customDevRpcRequest, expect } from "@moonwall/cli"; +import { ApiPromise } from "@polkadot/api"; +import { jumpBlocks, jumpSessions, jumpToSession } from "util/block"; +import { filterAndApply } from "@moonwall/util"; +import { EventRecord } from "@polkadot/types/interfaces"; +import { bool, u32, u8, Vec } from "@polkadot/types-codec"; +import { before } from "node:test"; +import { getHeaderFromRelay } from "util/relayInterface.ts"; + +describeSuite({ + id: "DTR1401", + title: "Paras inherent tests", + foundationMethods: "dev", + + testCases: ({ it, context }) => { + let polkadotJs: ApiPromise; + + before(async () => { + polkadotJs = context.polkadotJs(); + }); + + it({ + id: "E01", + title: "Paras heads should be updated every block", + test: async function () { + const parasHeadGenesis = await context.polkadotJs().query.paras.heads(2000); + await context.createBlock(); + // Send RPC call to enable para inherent candidate generation + await customDevRpcRequest("mock_enableParaInherentCandidate", []); + // Since collators are not assigned until session 2, we need to go till session 2 to actually see heads being injected + await jumpToSession(context, 3); + await context.createBlock(); + const parasHeadAfterOneBlock = await context.polkadotJs().query.paras.heads(2000); + expect(parasHeadAfterOneBlock).to.not.be.eq(parasHeadGenesis); + await context.createBlock(); + // we create one more block to test we are persisting candidates every block + const parasHeadAfterTwoBlocks = await context.polkadotJs().query.paras.heads(2000); + expect(parasHeadAfterOneBlock).to.not.be.eq(parasHeadAfterTwoBlocks); + const header2000 = await getHeaderFromRelay(context.polkadotJs(), 2000); + expect(header2000.number.toBigInt()).to.be.equal(31n); + }, + }); + }, +}); diff --git a/test/util/relayInterface.ts b/test/util/relayInterface.ts index 80c92cb5f..632ff206f 100644 --- a/test/util/relayInterface.ts +++ b/test/util/relayInterface.ts @@ -1,9 +1,16 @@ import { ApiPromise } from "@polkadot/api"; -import type { Header, ParaId } from "@polkadot/types/interfaces"; +import type { Header, ParaId, HeadData } from "@polkadot/types/interfaces"; +import { u8aToHex, u8aToU8a, isU8a, hexToU8a, compactToU8a, compactFromU8a, compactFromU8aLim } from "@polkadot/util" +import { bool, u32, u8, Bytes } from "@polkadot/types-codec"; +import { TypeRegistry } from "@polkadot/types"; export async function getHeaderFromRelay(relayApi: ApiPromise, paraId: ParaId): Promise
{ // Get the latest header from relay storage const encoded = await relayApi.query.paras.heads(paraId); - const header = await relayApi.createType("Header", encoded); + const registry = new TypeRegistry(); + const headerEncoded: HeadData = await relayApi.createType("HeadData", encoded.toHex()); + const nonEncodedHeader = new Bytes(registry, headerEncoded.toU8a(true)).toHex() + + const header = await relayApi.createType("SpRuntimeHeader", nonEncodedHeader); return header; -} +} \ No newline at end of file