Skip to content

Commit

Permalink
Merge branch 'master' into re-gius/weights-for-pallet-claims
Browse files Browse the repository at this point in the history
  • Loading branch information
re-gius authored Nov 1, 2024
2 parents 7593763 + fa52407 commit 9920277
Show file tree
Hide file tree
Showing 22 changed files with 873 additions and 260 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,5 @@ impl pallet_treasury::Config<FellowshipTreasuryInstance> for Runtime {
sp_core::ConstU8<1>,
ConstU32<1000>,
>;
type BlockNumberProvider = crate::System;
}
2 changes: 2 additions & 0 deletions polkadot/node/core/candidate-validation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ polkadot-node-subsystem-test-helpers = { workspace = true }
sp-maybe-compressed-blob = { workspace = true, default-features = true }
sp-core = { workspace = true, default-features = true }
polkadot-primitives-test-helpers = { workspace = true }
rstest = { workspace = true }
polkadot-primitives = { workspace = true, features = ["test"] }
166 changes: 137 additions & 29 deletions polkadot/node/core/candidate-validation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use polkadot_node_subsystem::{
overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult,
SubsystemSender,
};
use polkadot_node_subsystem_util as util;
use polkadot_node_subsystem_util::{self as util, runtime::ClaimQueueSnapshot};
use polkadot_overseer::ActiveLeavesUpdate;
use polkadot_parachain_primitives::primitives::ValidationResult as WasmValidationResult;
use polkadot_primitives::{
Expand All @@ -46,8 +46,9 @@ use polkadot_primitives::{
DEFAULT_LENIENT_PREPARATION_TIMEOUT, DEFAULT_PRECHECK_PREPARATION_TIMEOUT,
},
vstaging::{
CandidateDescriptorV2 as CandidateDescriptor, CandidateEvent,
transpose_claim_queue, CandidateDescriptorV2 as CandidateDescriptor, CandidateEvent,
CandidateReceiptV2 as CandidateReceipt,
CommittedCandidateReceiptV2 as CommittedCandidateReceipt,
},
AuthorityDiscoveryId, CandidateCommitments, ExecutorParams, Hash, PersistedValidationData,
PvfExecKind as RuntimePvfExecKind, PvfPrepKind, SessionIndex, ValidationCode,
Expand Down Expand Up @@ -148,6 +149,25 @@ impl<Context> CandidateValidationSubsystem {
}
}

// Returns the claim queue at relay parent and logs a warning if it is not available.
async fn claim_queue<Sender>(relay_parent: Hash, sender: &mut Sender) -> Option<ClaimQueueSnapshot>
where
Sender: SubsystemSender<RuntimeApiMessage>,
{
match util::runtime::fetch_claim_queue(sender, relay_parent).await {
Ok(maybe_cq) => maybe_cq,
Err(err) => {
gum::warn!(
target: LOG_TARGET,
?relay_parent,
?err,
"Claim queue not available"
);
None
},
}
}

fn handle_validation_message<S>(
mut sender: S,
validation_host: ValidationHost,
Expand All @@ -167,24 +187,40 @@ where
exec_kind,
response_sender,
..
} => async move {
let _timer = metrics.time_validate_from_exhaustive();
let res = validate_candidate_exhaustive(
validation_host,
validation_data,
validation_code,
candidate_receipt,
pov,
executor_params,
exec_kind,
&metrics,
)
.await;
} =>
async move {
let _timer = metrics.time_validate_from_exhaustive();
let relay_parent = candidate_receipt.descriptor.relay_parent();

let maybe_claim_queue = claim_queue(relay_parent, &mut sender).await;

let maybe_expected_session_index =
match util::request_session_index_for_child(relay_parent, &mut sender)
.await
.await
{
Ok(Ok(expected_session_index)) => Some(expected_session_index),
_ => None,
};

let res = validate_candidate_exhaustive(
maybe_expected_session_index,
validation_host,
validation_data,
validation_code,
candidate_receipt,
pov,
executor_params,
exec_kind,
&metrics,
maybe_claim_queue,
)
.await;

metrics.on_validation_event(&res);
let _ = response_sender.send(res);
}
.boxed(),
metrics.on_validation_event(&res);
let _ = response_sender.send(res);
}
.boxed(),
CandidateValidationMessage::PreCheck {
relay_parent,
validation_code_hash,
Expand Down Expand Up @@ -637,6 +673,7 @@ where
}

async fn validate_candidate_exhaustive(
maybe_expected_session_index: Option<SessionIndex>,
mut validation_backend: impl ValidationBackend + Send,
persisted_validation_data: PersistedValidationData,
validation_code: ValidationCode,
Expand All @@ -645,18 +682,41 @@ async fn validate_candidate_exhaustive(
executor_params: ExecutorParams,
exec_kind: PvfExecKind,
metrics: &Metrics,
maybe_claim_queue: Option<ClaimQueueSnapshot>,
) -> Result<ValidationResult, ValidationFailed> {
let _timer = metrics.time_validate_candidate_exhaustive();

let validation_code_hash = validation_code.hash();
let relay_parent = candidate_receipt.descriptor.relay_parent();
let para_id = candidate_receipt.descriptor.para_id();

gum::debug!(
target: LOG_TARGET,
?validation_code_hash,
?para_id,
"About to validate a candidate.",
);

// We only check the session index for backing.
match (exec_kind, candidate_receipt.descriptor.session_index()) {
(PvfExecKind::Backing | PvfExecKind::BackingSystemParas, Some(session_index)) => {
let Some(expected_session_index) = maybe_expected_session_index else {
let error = "cannot fetch session index from the runtime";
gum::warn!(
target: LOG_TARGET,
?relay_parent,
error,
);

return Err(ValidationFailed(error.into()))
};

if session_index != expected_session_index {
return Ok(ValidationResult::Invalid(InvalidCandidate::InvalidSessionIndex))
}
},
(_, _) => {},
};

if let Err(e) = perform_basic_checks(
&candidate_receipt.descriptor,
persisted_validation_data.max_pov_size,
Expand Down Expand Up @@ -754,15 +814,21 @@ async fn validate_candidate_exhaustive(
gum::info!(target: LOG_TARGET, ?para_id, "Invalid candidate (para_head)");
Ok(ValidationResult::Invalid(InvalidCandidate::ParaHeadHashMismatch))
} else {
let outputs = CandidateCommitments {
head_data: res.head_data,
upward_messages: res.upward_messages,
horizontal_messages: res.horizontal_messages,
new_validation_code: res.new_validation_code,
processed_downward_messages: res.processed_downward_messages,
hrmp_watermark: res.hrmp_watermark,
let committed_candidate_receipt = CommittedCandidateReceipt {
descriptor: candidate_receipt.descriptor.clone(),
commitments: CandidateCommitments {
head_data: res.head_data,
upward_messages: res.upward_messages,
horizontal_messages: res.horizontal_messages,
new_validation_code: res.new_validation_code,
processed_downward_messages: res.processed_downward_messages,
hrmp_watermark: res.hrmp_watermark,
},
};
if candidate_receipt.commitments_hash != outputs.hash() {

if candidate_receipt.commitments_hash !=
committed_candidate_receipt.commitments.hash()
{
gum::info!(
target: LOG_TARGET,
?para_id,
Expand All @@ -773,7 +839,48 @@ async fn validate_candidate_exhaustive(
// invalid.
Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))
} else {
Ok(ValidationResult::Valid(outputs, (*persisted_validation_data).clone()))
let core_index = candidate_receipt.descriptor.core_index();

match (core_index, exec_kind) {
// Core selectors are optional for V2 descriptors, but we still check the
// descriptor core index.
(
Some(_core_index),
PvfExecKind::Backing | PvfExecKind::BackingSystemParas,
) => {
let Some(claim_queue) = maybe_claim_queue else {
let error = "cannot fetch the claim queue from the runtime";
gum::warn!(
target: LOG_TARGET,
?relay_parent,
error
);

return Err(ValidationFailed(error.into()))
};

if let Err(err) = committed_candidate_receipt
.check_core_index(&transpose_claim_queue(claim_queue.0))
{
gum::warn!(
target: LOG_TARGET,
?err,
candidate_hash = ?candidate_receipt.hash(),
"Candidate core index is invalid",
);
return Ok(ValidationResult::Invalid(
InvalidCandidate::InvalidCoreIndex,
))
}
},
// No checks for approvals and disputes
(_, _) => {},
}

Ok(ValidationResult::Valid(
committed_candidate_receipt.commitments,
(*persisted_validation_data).clone(),
))
}
},
}
Expand Down Expand Up @@ -1003,6 +1110,7 @@ fn perform_basic_checks(
return Err(InvalidCandidate::CodeHashMismatch)
}

// No-op for `v2` receipts.
if let Err(()) = candidate.check_collator_signature() {
return Err(InvalidCandidate::BadSignature)
}
Expand Down
Loading

0 comments on commit 9920277

Please sign in to comment.