diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index d3155177553cc6e953e91dd11b14df64a292829d..a07537f2448f702d8b38ca0231fa3abbc55fcffe 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -333,6 +333,7 @@ async fn handle_new_activations<Context: SubsystemContext>( persisted_validation_data_hash, pov_hash, erasure_root, + para_head: commitments.head_data.hash(), }, }; @@ -738,6 +739,7 @@ mod tests { persisted_validation_data_hash: expect_validation_data_hash, pov_hash: expect_pov_hash, erasure_root: Default::default(), // this isn't something we're checking right now + para_head: test_collation().head_data.hash(), }; assert_eq!(sent_messages.len(), 1); diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index eec666ded1203c17768bf962d5958ab00d00bd6a..47405a208e9ff383c0e4f2472a3b0028c72d4360 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -459,6 +459,10 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>( Ok(ValidationResult::Invalid(InvalidCandidate::ExecutionError(e.to_string()))), Err(ValidationError::Internal(e)) => Err(ValidationFailed(e.to_string())), Ok(res) => { + if res.head_data.hash() != descriptor.para_head { + return Ok(ValidationResult::Invalid(InvalidCandidate::ParaHeadHashMismatch)); + } + let outputs = CandidateCommitments { head_data: res.head_data, upward_messages: res.upward_messages, @@ -887,15 +891,17 @@ mod tests { let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; let pov = PoV { block_data: BlockData(vec![1; 32]) }; + let head_data = HeadData(vec![1, 1, 1]); let mut descriptor = CandidateDescriptor::default(); descriptor.pov_hash = pov.hash(); + descriptor.para_head = head_data.hash(); collator_sign(&mut descriptor, Sr25519Keyring::Alice); assert!(perform_basic_checks(&descriptor, validation_data.max_pov_size, &pov).is_ok()); let validation_result = WasmValidationResult { - head_data: HeadData(vec![1, 1, 1]), + head_data, new_validation_code: Some(vec![2, 2, 2].into()), upward_messages: Vec::new(), horizontal_messages: Vec::new(), diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index e2195f59e2a16bec13a661559bce848ae4abeb47..5fb3f49308fb1056c16fef1a638003cc9fd4efaa 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -150,6 +150,8 @@ pub enum InvalidCandidate { HashMismatch, /// Bad collator signature. BadSignature, + /// Para head hash does not match. + ParaHeadHashMismatch, } /// Result of the validation of the candidate. diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index a9b8f13c800d19d68d5fa1b51a3219dd8eae72cb..991bc260fb08c39387b716b60a93f0837323b19e 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -38,6 +38,15 @@ pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber; #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Default, Hash))] pub struct HeadData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>); +#[cfg(feature = "std")] +impl HeadData { + /// Returns the hash of this head data. + pub fn hash(&self) -> Hash { + use sp_runtime::traits::Hash; + sp_runtime::traits::BlakeTwo256::hash(&self.0) + } +} + /// Parachain validation code. #[derive(Default, PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, derive_more::From)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))] diff --git a/polkadot/primitives/src/v1.rs b/polkadot/primitives/src/v1.rs index 30a4b392656080e656856277ea774b49024d1a47..cf5cc1533a8ad02c236484fa0092ac049d03a20b 100644 --- a/polkadot/primitives/src/v1.rs +++ b/polkadot/primitives/src/v1.rs @@ -211,6 +211,8 @@ pub struct CandidateDescriptor<H = Hash> { /// Signature on blake2-256 of components of this receipt: /// The parachain index, the relay parent, the validation data hash, and the pov_hash. pub signature: CollatorSignature, + /// Hash of the para header that is being generated by this candidate. + pub para_head: Hash, } impl<H: AsRef<[u8]>> CandidateDescriptor<H> { diff --git a/polkadot/roadmap/implementers-guide/src/types/candidate.md b/polkadot/roadmap/implementers-guide/src/types/candidate.md index 1e65daab532f94f0ccf74122a027ba8df3c0dc59..0ba556a20d1bc00e8bcb9f49e88c359500379d3c 100644 --- a/polkadot/roadmap/implementers-guide/src/types/candidate.md +++ b/polkadot/roadmap/implementers-guide/src/types/candidate.md @@ -85,6 +85,8 @@ struct CandidateDescriptor { /// Signature on blake2-256 of components of this receipt: /// The parachain index, the relay parent, the validation data hash, and the pov_hash. signature: CollatorSignature, + /// Hash of the para header that is being generated by this candidate. + para_head: Hash, } ```