Do not use rely on the block initialization when calling runtime APIs (#2123)

* Don't initialize block when calling runtime APIs

* Adapt check_validation_outputs

We split the code path for the inclusion and for the commitments checking.

* Slap #[skip_initialize_block] on safe runtime APIs

That is, those that should not be affected by this attribute

* Make `Scheduled` not ephemeral

So that it is persisted in the storage and ready to be inspected
by the runtime APIs. This is in contrast to what was before, where we
would remove the storage entry and then rely on the scheduling performed
by `on_initialize` again.

* Add a big fat comment

* Typos

Co-authored-by: Robert Habermeier <rphmeier@gmail.com>

* Move session change to the end of the current block

Previously, it was the beginning of the next block. This allows us to
put #[skip_initialize_block]

* Update tests

* Fix a test in paras registrar

Also refactor it a bit so the next time there are more chances this kind
of issue is diagnosed quicker.

* Add for_runtime_api to inclusion's check_validation_outputs

Co-authored-by: Robert Habermeier <rphmeier@gmail.com>
This commit is contained in:
Sergei Shulepov
2020-12-22 00:02:22 +01:00
committed by GitHub
parent 01d271caeb
commit 4405f52e2d
8 changed files with 114 additions and 77 deletions
+26 -9
View File
@@ -399,7 +399,12 @@ impl<T: Config> Module<T> {
let validators = Validators::get();
let parent_hash = <frame_system::Module<T>>::parent_hash();
let check_cx = CandidateCheckContext::<T>::new();
// At the moment we assume (and in fact enforce, below) that the relay-parent is always one
// before of the block where we include a candidate (i.e. this code path).
let now = <frame_system::Module<T>>::block_number();
let relay_parent_number = now - One::one();
let check_cx = CandidateCheckContext::<T>::new(now, relay_parent_number);
// do all checks before writing storage.
let core_indices_and_backers = {
@@ -483,7 +488,10 @@ impl<T: Config> Module<T> {
{
// this should never fail because the para is registered
let persisted_validation_data =
match crate::util::make_persisted_validation_data::<T>(para_id) {
match crate::util::make_persisted_validation_data::<T>(
para_id,
relay_parent_number,
) {
Some(l) => l,
None => {
// We don't want to error out here because it will
@@ -592,7 +600,7 @@ impl<T: Config> Module<T> {
hash: candidate_hash,
descriptor,
availability_votes,
relay_parent_number: check_cx.relay_parent_number,
relay_parent_number,
backers,
backed_in_number: check_cx.now,
});
@@ -603,11 +611,17 @@ impl<T: Config> Module<T> {
}
/// Run the acceptance criteria checks on the given candidate commitments.
pub(crate) fn check_validation_outputs(
pub(crate) fn check_validation_outputs_for_runtime_api(
para_id: ParaId,
validation_outputs: primitives::v1::CandidateCommitments,
) -> bool {
if let Err(err) = CandidateCheckContext::<T>::new().check_validation_outputs(
// This function is meant to be called from the runtime APIs against the relay-parent, hence
// `relay_parent_number` is equal to `now`.
let now = <frame_system::Module<T>>::block_number();
let relay_parent_number = now;
let check_cx = CandidateCheckContext::<T>::new(now, relay_parent_number);
if let Err(err) = check_cx.check_validation_outputs(
para_id,
&validation_outputs.head_data,
&validation_outputs.new_validation_code,
@@ -812,12 +826,11 @@ struct CandidateCheckContext<T: Config> {
}
impl<T: Config> CandidateCheckContext<T> {
fn new() -> Self {
let now = <frame_system::Module<T>>::block_number();
fn new(now: T::BlockNumber, relay_parent_number: T::BlockNumber) -> Self {
Self {
config: <configuration::Module<T>>::config(),
now,
relay_parent_number: now - One::one(),
relay_parent_number,
}
}
@@ -1111,8 +1124,12 @@ mod tests {
}
fn make_vdata_hash(para_id: ParaId) -> Option<Hash> {
let relay_parent_number = <frame_system::Module<Test>>::block_number() - 1;
let persisted_validation_data
= crate::util::make_persisted_validation_data::<Test>(para_id)?;
= crate::util::make_persisted_validation_data::<Test>(
para_id,
relay_parent_number,
)?;
Some(persisted_validation_data.hash())
}