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

Commit

Permalink
(async backing) restore CheckInherents for backwards-compatibility (#…
Browse files Browse the repository at this point in the history
…2977)

* bring back timestamp

* Restore CheckInherents

* revert to empty CheckInherents

* make CheckInherents optional
  • Loading branch information
slumber authored Aug 8, 2023
1 parent 3dd4757 commit 84565ec
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 11 deletions.
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)
}
}

0 comments on commit 84565ec

Please sign in to comment.