Improve diagnostics for the ValidationOutputs checker / inclusion (#1926)

* Improve diagnostics for acceptance criteria failures during inclusion

* Initialize the runtime logger just before logging during inclusion

* Formatting suggestions

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Missed one suggestion

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Sergei Shulepov
2020-11-11 11:34:52 +01:00
committed by GitHub
parent fb6b94eaf0
commit dd4d8e24e0
8 changed files with 402 additions and 206 deletions
+84 -51
View File
@@ -186,8 +186,9 @@ decl_module! {
}
}
impl<T: Trait> Module<T> {
const LOG_TARGET: &str = "parachains_runtime_inclusion";
impl<T: Trait> Module<T> {
/// Block initialization logic, called by initializer.
pub(crate) fn initializer_initialize(_now: T::BlockNumber) -> Weight { 0 }
@@ -400,7 +401,7 @@ impl<T: Trait> Module<T> {
// In the meantime, we do certain sanity checks on the candidates and on the scheduled
// list.
'a:
for candidate in &candidates {
for (candidate_idx, candidate) in candidates.iter().enumerate() {
let para_id = candidate.descriptor().para_id;
// we require that the candidate is in the context of the parent block.
@@ -413,15 +414,27 @@ impl<T: Trait> Module<T> {
Error::<T>::NotCollatorSigned,
);
check_cx.check_validation_outputs(
para_id,
&candidate.candidate.commitments.head_data,
&candidate.candidate.commitments.new_validation_code,
candidate.candidate.commitments.processed_downward_messages,
&candidate.candidate.commitments.upward_messages,
T::BlockNumber::from(candidate.candidate.commitments.hrmp_watermark),
&candidate.candidate.commitments.horizontal_messages,
)?;
if let Err(err) = check_cx
.check_validation_outputs(
para_id,
&candidate.candidate.commitments.head_data,
&candidate.candidate.commitments.new_validation_code,
candidate.candidate.commitments.processed_downward_messages,
&candidate.candidate.commitments.upward_messages,
T::BlockNumber::from(candidate.candidate.commitments.hrmp_watermark),
&candidate.candidate.commitments.horizontal_messages,
)
{
frame_support::debug::RuntimeLogger::init();
log::debug!(
target: LOG_TARGET,
"Validation outputs checking during inclusion of a candidate {} for parachain `{}` failed: {:?}",
candidate_idx,
u32::from(para_id),
err,
);
Err(err.strip_into_dispatch_err::<T>())?;
};
for (i, assignment) in scheduled[skip..].iter().enumerate() {
check_assignment_in_order(assignment)?;
@@ -542,13 +555,11 @@ impl<T: Trait> Module<T> {
}
/// Run the acceptance criteria checks on the given candidate commitments.
///
/// Returns an 'Err` if any of the checks doesn't pass.
pub(crate) fn check_validation_outputs(
para_id: ParaId,
validation_outputs: primitives::v1::ValidationOutputs,
) -> Result<(), DispatchError> {
CandidateCheckContext::<T>::new().check_validation_outputs(
) -> bool {
if let Err(err) = CandidateCheckContext::<T>::new().check_validation_outputs(
para_id,
&validation_outputs.head_data,
&validation_outputs.new_validation_code,
@@ -556,7 +567,18 @@ impl<T: Trait> Module<T> {
&validation_outputs.upward_messages,
T::BlockNumber::from(validation_outputs.hrmp_watermark),
&validation_outputs.horizontal_messages,
)
) {
frame_support::debug::RuntimeLogger::init();
log::debug!(
target: LOG_TARGET,
"Validation outputs checking for parachain `{}` failed: {:?}",
u32::from(para_id),
err,
);
false
} else {
true
}
}
fn enact_candidate(
@@ -692,6 +714,34 @@ const fn availability_threshold(n_validators: usize) -> usize {
threshold
}
#[derive(derive_more::From, Debug)]
enum AcceptanceCheckErr<BlockNumber> {
HeadDataTooLarge,
PrematureCodeUpgrade,
NewCodeTooLarge,
ProcessedDownwardMessages(router::ProcessedDownwardMessagesAcceptanceErr),
UpwardMessages(router::UpwardMessagesAcceptanceCheckErr),
HrmpWatermark(router::HrmpWatermarkAcceptanceErr<BlockNumber>),
OutboundHrmp(router::OutboundHrmpAcceptanceErr),
}
impl<BlockNumber> AcceptanceCheckErr<BlockNumber> {
/// Returns the same error so that it can be threaded through a needle of `DispatchError` and
/// ultimately returned from a `Dispatchable`.
fn strip_into_dispatch_err<T: Trait>(self) -> Error<T> {
use AcceptanceCheckErr::*;
match self {
HeadDataTooLarge => Error::<T>::HeadDataTooLarge,
PrematureCodeUpgrade => Error::<T>::PrematureCodeUpgrade,
NewCodeTooLarge => Error::<T>::NewCodeTooLarge,
ProcessedDownwardMessages(_) => Error::<T>::IncorrectDownwardMessageHandling,
UpwardMessages(_) => Error::<T>::InvalidUpwardMessages,
HrmpWatermark(_) => Error::<T>::HrmpWatermarkMishandling,
OutboundHrmp(_) => Error::<T>::InvalidOutboundHrmp,
}
}
}
/// A collection of data required for checking a candidate.
struct CandidateCheckContext<T: Trait> {
config: configuration::HostConfiguration<T::BlockNumber>,
@@ -720,10 +770,10 @@ impl<T: Trait> CandidateCheckContext<T> {
upward_messages: &[primitives::v1::UpwardMessage],
hrmp_watermark: T::BlockNumber,
horizontal_messages: &[primitives::v1::OutboundHrmpMessage<ParaId>],
) -> Result<(), DispatchError> {
) -> Result<(), AcceptanceCheckErr<T::BlockNumber>> {
ensure!(
head_data.0.len() <= self.config.max_head_data_size as _,
Error::<T>::HeadDataTooLarge
AcceptanceCheckErr::HeadDataTooLarge,
);
// if any, the code upgrade attempt is allowed.
@@ -734,45 +784,28 @@ impl<T: Trait> CandidateCheckContext<T> {
&& self.relay_parent_number.saturating_sub(last)
>= self.config.validation_upgrade_frequency
});
ensure!(valid_upgrade_attempt, Error::<T>::PrematureCodeUpgrade);
ensure!(
valid_upgrade_attempt,
AcceptanceCheckErr::PrematureCodeUpgrade,
);
ensure!(
new_validation_code.0.len() <= self.config.max_code_size as _,
Error::<T>::NewCodeTooLarge
AcceptanceCheckErr::NewCodeTooLarge,
);
}
// check if the candidate passes the messaging acceptance criteria
ensure!(
<router::Module<T>>::check_processed_downward_messages(
para_id,
processed_downward_messages,
),
Error::<T>::IncorrectDownwardMessageHandling,
);
ensure!(
<router::Module<T>>::check_upward_messages(
&self.config,
para_id,
upward_messages,
),
Error::<T>::InvalidUpwardMessages,
);
ensure!(
<router::Module<T>>::check_hrmp_watermark(
para_id,
self.relay_parent_number,
hrmp_watermark,
),
Error::<T>::HrmpWatermarkMishandling,
);
ensure!(
<router::Module<T>>::check_outbound_hrmp(
&self.config,
para_id,
horizontal_messages,
),
Error::<T>::InvalidOutboundHrmp,
);
<router::Module<T>>::check_processed_downward_messages(
para_id,
processed_downward_messages,
)?;
<router::Module<T>>::check_upward_messages(&self.config, para_id, upward_messages)?;
<router::Module<T>>::check_hrmp_watermark(
para_id,
self.relay_parent_number,
hrmp_watermark,
)?;
<router::Module<T>>::check_outbound_hrmp(&self.config, para_id, horizontal_messages)?;
Ok(())
}