diff --git a/runtime/parachains/src/inclusion/mod.rs b/runtime/parachains/src/inclusion/mod.rs index 695cd351b8e6..5ec6b807a38d 100644 --- a/runtime/parachains/src/inclusion/mod.rs +++ b/runtime/parachains/src/inclusion/mod.rs @@ -522,7 +522,26 @@ impl Pallet { 'next_backed_candidate: for (candidate_idx, backed_candidate) in candidates.iter().enumerate() { - check_ctx.verify_backed_candidate(parent_hash, candidate_idx, backed_candidate)?; + match check_ctx.verify_backed_candidate( + parent_hash, + parent_storage_root, + candidate_idx, + backed_candidate, + )? { + Err(FailedToCreatePVD) => { + log::debug!( + target: LOG_TARGET, + "Failed to create PVD for candidate {} on relay parent {:?}", + candidate_idx, + parent_hash, + ); + // We don't want to error out here because it will + // brick the relay-chain. So we return early without + // doing anything. + return Ok(ProcessedCandidates::default()) + }, + Ok(rpn) => rpn, + } let para_id = backed_candidate.descriptor().para_id; let mut backers = bitvec::bitvec![BitOrderLsb0, u8; 0; validators.len()]; @@ -538,32 +557,6 @@ impl Pallet { ); } - { - // this should never fail because the para is registered - let persisted_validation_data = - match crate::util::make_persisted_validation_data::( - para_id, - relay_parent_number, - parent_storage_root, - ) { - Some(l) => l, - None => { - // We don't want to error out here because it will - // brick the relay-chain. So we return early without - // doing anything. - return Ok(ProcessedCandidates::default()) - }, - }; - - let expected = persisted_validation_data.hash(); - - ensure!( - expected == - backed_candidate.descriptor().persisted_validation_data_hash, - Error::::ValidationDataHashMismatch, - ); - } - ensure!( >::get(¶_id).is_none() && >::get(¶_id).is_none(), @@ -945,6 +938,10 @@ pub(crate) struct CandidateCheckContext { relay_parent_number: T::BlockNumber, } +/// An error indicating that creating Persisted Validation Data failed +/// while checking a candidate's validity. +pub(crate) struct FailedToCreatePVD; + impl CandidateCheckContext { pub(crate) fn new(now: T::BlockNumber, relay_parent_number: T::BlockNumber) -> Self { Self { config: >::config(), now, relay_parent_number } @@ -960,10 +957,32 @@ impl CandidateCheckContext { pub(crate) fn verify_backed_candidate( &self, parent_hash: ::Hash, + parent_storage_root: T::Hash, candidate_idx: usize, backed_candidate: &BackedCandidate<::Hash>, - ) -> Result<(), Error> { + ) -> Result, Error> { let para_id = backed_candidate.descriptor().para_id; + let now = >::block_number(); + let relay_parent_number = now - One::one(); + + { + // this should never fail because the para is registered + let persisted_validation_data = match crate::util::make_persisted_validation_data::( + para_id, + relay_parent_number, + parent_storage_root, + ) { + Some(l) => l, + None => return Ok(Err(FailedToCreatePVD)), + }; + + let expected = persisted_validation_data.hash(); + + ensure!( + expected == backed_candidate.descriptor().persisted_validation_data_hash, + Error::::ValidationDataHashMismatch, + ); + } // we require that the candidate is in the context of the parent block. ensure!( @@ -1007,7 +1026,7 @@ impl CandidateCheckContext { ); Err(err.strip_into_dispatch_err::())?; }; - Ok(()) + Ok(Ok(())) } /// Check the given outputs after candidate validation on whether it passes the acceptance diff --git a/runtime/parachains/src/paras_inherent/mod.rs b/runtime/parachains/src/paras_inherent/mod.rs index 66ce3cc5dfb8..6a690f2b8541 100644 --- a/runtime/parachains/src/paras_inherent/mod.rs +++ b/runtime/parachains/src/paras_inherent/mod.rs @@ -709,6 +709,7 @@ impl Pallet { let scheduled = >::scheduled(); let relay_parent_number = now - One::one(); + let parent_storage_root = parent_header.state_root().clone(); let check_ctx = CandidateCheckContext::::new(now, relay_parent_number); let backed_candidates = sanitize_backed_candidates::( @@ -719,13 +720,21 @@ impl Pallet { -> bool { // never include a concluded-invalid candidate concluded_invalid_disputes.contains(&backed_candidate.hash()) || - // Instead of checking the candidates with code upgrades twice - // move the checking up here and skip it in the training wheels fallback. - // That way we avoid possible duplicate checks while assuring all - // backed candidates fine to pass on. - check_ctx - .verify_backed_candidate(parent_hash, candidate_idx, backed_candidate) - .is_err() + // Instead of checking the candidates with code upgrades twice + // move the checking up here and skip it in the training wheels fallback. + // That way we avoid possible duplicate checks while assuring all + // backed candidates fine to pass on. + { + match check_ctx.verify_backed_candidate( + parent_hash, + parent_storage_root, + candidate_idx, + backed_candidate, + ) { + Err(_) | Ok(Err(_)) => true, + Ok(Ok(_)) => false, + } + } }, &scheduled[..], );