Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

(async backing) restore CheckInherents for backwards-compatibility #2977

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ members = [
"parachain-template/runtime",
"primitives/core",
"primitives/parachain-inherent",
"primitives/timestamp",
"primitives/utility",
"polkadot-parachain",
"parachains/common",
Expand Down
29 changes: 21 additions & 8 deletions pallets/parachain-system/proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

use proc_macro2::{Span, TokenStream};
use proc_macro2::Span;
use proc_macro_crate::{crate_name, FoundCrate};
use syn::{
parse::{Parse, ParseStream},
Expand All @@ -25,17 +25,20 @@ use syn::{
mod keywords {
syn::custom_keyword!(Runtime);
syn::custom_keyword!(BlockExecutor);
syn::custom_keyword!(CheckInherents);
}

struct Input {
runtime: Path,
block_executor: Path,
check_inherents: Option<Path>,
}

impl Parse for Input {
fn parse(input: ParseStream) -> Result<Self, Error> {
let mut runtime = None;
let mut block_executor = None;
let mut check_inherents = None;

fn parse_inner<KW: Parse + Spanned>(
input: ParseStream,
Expand All @@ -56,26 +59,24 @@ impl Parse for Input {
}
}

while runtime.is_none() || block_executor.is_none() {
while !input.is_empty() || runtime.is_none() || block_executor.is_none() {
let lookahead = input.lookahead1();

if lookahead.peek(keywords::Runtime) {
parse_inner::<keywords::Runtime>(input, &mut runtime)?;
} else if lookahead.peek(keywords::BlockExecutor) {
parse_inner::<keywords::BlockExecutor>(input, &mut block_executor)?;
} else if lookahead.peek(keywords::CheckInherents) {
parse_inner::<keywords::CheckInherents>(input, &mut check_inherents)?;
} else {
return Err(lookahead.error())
}
}

let rest = input.parse::<TokenStream>()?;
if !rest.is_empty() {
return Err(Error::new(rest.span(), "Unexpected input data"))
}

Ok(Self {
runtime: runtime.expect("Everything is parsed before; qed"),
block_executor: block_executor.expect("Everything is parsed before; qed"),
check_inherents,
})
}
}
Expand All @@ -91,7 +92,7 @@ fn crate_() -> Result<Ident, Error> {

#[proc_macro]
pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let Input { runtime, block_executor } = match syn::parse(input) {
let Input { runtime, block_executor, check_inherents } = match syn::parse(input) {
Ok(t) => t,
Err(e) => return e.into_compile_error().into(),
};
Expand All @@ -101,6 +102,17 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To
Err(e) => return e.into_compile_error().into(),
};

let check_inherents = match check_inherents {
Some(_check_inherents) => {
quote::quote! { #_check_inherents }
},
None => {
quote::quote! {
#crate_::DummyCheckInherents<<#runtime as #crate_::validate_block::GetRuntimeBlockType>::RuntimeBlock>
}
},
};

if cfg!(not(feature = "std")) {
quote::quote! {
#[doc(hidden)]
Expand All @@ -127,6 +139,7 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To
<#runtime as #crate_::validate_block::GetRuntimeBlockType>::RuntimeBlock,
#block_executor,
#runtime,
#check_inherents,
>(params);

#crate_::validate_block::polkadot_parachain::write_result(&res)
Expand Down
34 changes: 33 additions & 1 deletion pallets/parachain-system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor};
use polkadot_parachain::primitives::RelayChainBlockNumber;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{BlockNumberProvider, Hash},
traits::{Block as BlockT, BlockNumberProvider, Hash},
transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionSource, TransactionValidity,
ValidTransaction,
Expand Down Expand Up @@ -86,10 +86,12 @@ pub use consensus_hook::{ConsensusHook, ExpectParentIncluded};
/// ```
/// struct BlockExecutor;
/// struct Runtime;
/// struct CheckInherents;
///
/// cumulus_pallet_parachain_system::register_validate_block! {
/// Runtime = Runtime,
/// BlockExecutor = Executive,
/// CheckInherents = CheckInherents,
/// }
///
/// # fn main() {}
Expand Down Expand Up @@ -1497,6 +1499,36 @@ impl<T: Config> UpwardMessageSender for Pallet<T> {
}
}

/// Something that can check the inherents of a block.
#[cfg_attr(
feature = "parameterized-consensus-hook",
deprecated = "consider switching to `cumulus-pallet-parachain-system::ConsensusHook`"
)]
pub trait CheckInherents<Block: BlockT> {
/// Check all inherents of the block.
///
/// This function gets passed all the extrinsics of the block, so it is up to the callee to
/// identify the inherents. The `validation_data` can be used to access the
fn check_inherents(
block: &Block,
validation_data: &RelayChainStateProof,
) -> frame_support::inherent::CheckInherentsResult;
}

/// Struct that always returns `Ok` on inherents check, needed for backwards-compatibility.
#[doc(hidden)]
pub struct DummyCheckInherents<Block>(sp_std::marker::PhantomData<Block>);

#[allow(deprecated)]
impl<Block: BlockT> CheckInherents<Block> for DummyCheckInherents<Block> {
fn check_inherents(
_: &Block,
_: &RelayChainStateProof,
) -> frame_support::inherent::CheckInherentsResult {
sp_inherents::CheckInherentsResult::new()
}
}

/// Something that should be informed about system related events.
///
/// This includes events like [`on_validation_data`](Self::on_validation_data) that is being
Expand Down
33 changes: 31 additions & 2 deletions pallets/parachain-system/src/validate_block/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,20 @@ fn with_externalities<F: FnOnce(&mut dyn Externalities) -> R, R>(f: F) -> R {
/// we have the in-memory database that contains all the values from the state of the parachain
/// that we require to verify the block.
///
/// 5. The last step is to execute the entire block in the machinery we just have setup. Executing
/// 5. We are going to run `check_inherents`. This is important to check stuff like the timestamp
/// matching the real world time.
///
/// 6. The last step is to execute the entire block in the machinery we just have setup. Executing
/// the blocks include running all transactions in the block against our in-memory database and
/// ensuring that the final storage root matches the storage root in the header of the block. In the
/// end we return back the [`ValidationResult`] with all the required information for the validator.
#[doc(hidden)]
pub fn validate_block<B: BlockT, E: ExecuteBlock<B>, PSC: crate::Config>(
pub fn validate_block<
B: BlockT,
E: ExecuteBlock<B>,
PSC: crate::Config,
CI: crate::CheckInherents<B>,
>(
MemoryOptimizedValidationParams {
block_data,
parent_head,
Expand Down Expand Up @@ -159,6 +167,27 @@ where
sp_io::offchain_index::host_clear.replace_implementation(host_offchain_index_clear),
);

run_with_externalities::<B, _, _>(&backend, || {
let relay_chain_proof = crate::RelayChainStateProof::new(
PSC::SelfParaId::get(),
inherent_data.validation_data.relay_parent_storage_root,
inherent_data.relay_chain_state.clone(),
)
.expect("Invalid relay chain state proof");

let res = CI::check_inherents(&block, &relay_chain_proof);

if !res.ok() {
if log::log_enabled!(log::Level::Error) {
res.into_errors().for_each(|e| {
log::error!("Checking inherent with identifier `{:?}` failed", e.0)
});
}

panic!("Checking inherents failed");
}
});

run_with_externalities::<B, _, _>(&backend, || {
let head_data = HeadData(block.header().encode());

Expand Down
27 changes: 27 additions & 0 deletions primitives/timestamp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "cumulus-primitives-timestamp"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
description = "Provides timestamp related functionality for parachains."

[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] }
futures = "0.3.28"

# Substrate
sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }

# Cumulus
cumulus-primitives-core = { path = "../core", default-features = false }

[features]
default = [ "std" ]
std = [
"sp-inherents/std",
"sp-std/std",
"sp-timestamp/std",
"cumulus-primitives-core/std",
]
70 changes: 70 additions & 0 deletions primitives/timestamp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.

// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

//! Cumulus timestamp related primitives.
//!
//! Provides a [`InherentDataProvider`] that should be used in the validation phase of the parachain.
//! It will be used to create the inherent data and that will be used to check the inherents inside
//! the parachain block (in this case the timestamp inherent). As we don't have access to any clock
//! from the runtime the timestamp is always passed as an inherent into the runtime. To check this
//! inherent when validating the block, we will use the relay chain slot. As the relay chain slot
//! is derived from a timestamp, we can easily convert it back to a timestamp by muliplying it with
//! the slot duration. By comparing the relay chain slot derived timestamp with the timestamp we can
//! ensure that the parachain timestamp is reasonable.

#![cfg_attr(not(feature = "std"), no_std)]

use cumulus_primitives_core::relay_chain::Slot;
use sp_inherents::{Error, InherentData};
use sp_std::time::Duration;

pub use sp_timestamp::{InherentType, INHERENT_IDENTIFIER};

/// The inherent data provider for the timestamp.
///
/// This should be used in the runtime when checking the inherents in the validation phase of the
/// parachain.
pub struct InherentDataProvider {
relay_chain_slot: Slot,
relay_chain_slot_duration: Duration,
}

impl InherentDataProvider {
/// Create `Self` from the given relay chain slot and slot duration.
pub fn from_relay_chain_slot_and_duration(
relay_chain_slot: Slot,
relay_chain_slot_duration: Duration,
) -> Self {
Self { relay_chain_slot, relay_chain_slot_duration }
}

/// Create the inherent data.
pub fn create_inherent_data(&self) -> Result<InherentData, Error> {
let mut inherent_data = InherentData::new();
self.provide_inherent_data(&mut inherent_data).map(|_| inherent_data)
}

/// Provide the inherent data into the given `inherent_data`.
pub fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> {
// As the parachain starts building at around `relay_chain_slot + 1` we use that slot to
// calculate the timestamp.
let data: InherentType = ((*self.relay_chain_slot + 1) *
self.relay_chain_slot_duration.as_millis() as u64)
.into();

inherent_data.put_data(INHERENT_IDENTIFIER, &data)
}
}