Bring support for calling check_inherents (#490)

* Start

* More work

* Add proc-macro for `validate_block`

* Make everything compile

* Add some test
This commit is contained in:
Bastian Köcher
2021-06-12 19:21:46 +01:00
committed by GitHub
parent c5819c9e78
commit 2dc281b482
20 changed files with 684 additions and 326 deletions
@@ -16,14 +16,12 @@
//! The actual implementation of the validate block functionality.
use frame_support::traits::ExecuteBlock;
use sp_runtime::traits::{Block as BlockT, HashFor, Header as HeaderT, NumberFor};
use frame_support::traits::{ExecuteBlock, ExtrinsicCall, IsSubType, Get};
use sp_runtime::traits::{Block as BlockT, Extrinsic, HashFor, Header as HeaderT, NumberFor};
use sp_io::KillChildStorageResult;
use sp_std::prelude::*;
use hash_db::{HashDB, EMPTY_PREFIX};
use polkadot_parachain::primitives::{HeadData, ValidationParams, ValidationResult};
use codec::{Decode, Encode};
@@ -32,12 +30,9 @@ use sp_core::storage::ChildInfo;
use sp_externalities::{set_and_run_with_externalities, Externalities};
use sp_trie::MemoryDB;
type Ext<'a, B> = sp_state_machine::Ext<
'a,
HashFor<B>,
NumberFor<B>,
sp_state_machine::TrieBackend<MemoryDB<HashFor<B>>, HashFor<B>>,
>;
type TrieBackend<B> = sp_state_machine::TrieBackend<MemoryDB<HashFor<B>>, HashFor<B>>;
type Ext<'a, B> = sp_state_machine::Ext<'a, HashFor<B>, NumberFor<B>, TrieBackend<B>>;
fn with_externalities<F: FnOnce(&mut dyn Externalities) -> R, R>(f: F) -> R {
sp_externalities::with_externalities(f).expect("Environmental externalities not set.")
@@ -45,9 +40,18 @@ fn with_externalities<F: FnOnce(&mut dyn Externalities) -> R, R>(f: F) -> R {
/// Validate a given parachain block on a 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>,
>(
params: ValidationParams,
) -> ValidationResult {
) -> ValidationResult
where
B::Extrinsic: ExtrinsicCall,
<B::Extrinsic as Extrinsic>::Call: IsSubType<crate::Call<PSC>>,
{
let block_data =
cumulus_primitives_core::ParachainBlockData::<B>::decode(&mut &params.block_data.0[..])
.expect("Invalid parachain block data");
@@ -77,9 +81,6 @@ pub fn validate_block<B: BlockT, E: ExecuteBlock<B>, PSC: crate::Config>(
};
let backend = sp_state_machine::TrieBackend::new(db, root);
let mut overlay = sp_state_machine::OverlayedChanges::default();
let mut cache = Default::default();
let mut ext = Ext::<B>::new(&mut overlay, &mut cache, &backend);
let _guard = (
// Replace storage calls with our own implementations
@@ -121,7 +122,38 @@ pub fn validate_block<B: BlockT, E: ExecuteBlock<B>, PSC: crate::Config>(
sp_io::offchain_index::host_clear.replace_implementation(host_offchain_index_clear),
);
set_and_run_with_externalities(&mut ext, || {
let inherent_data = block
.extrinsics()
.iter()
.filter_map(|e| e.call().is_sub_type())
.find_map(|c| match c {
crate::Call::set_validation_data(validation_data) => Some(validation_data.clone()),
_ => None,
})
.expect("Could not find `set_validation_data` inherent");
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.extrinsics(), &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, || {
super::set_and_run_with_validation_params(params, || {
E::execute_block(block);
@@ -143,6 +175,18 @@ pub fn validate_block<B: BlockT, E: ExecuteBlock<B>, PSC: crate::Config>(
})
}
/// Run the given closure with the externalities set.
fn run_with_externalities<B: BlockT, R, F: FnOnce() -> R>(
backend: &TrieBackend<B>,
execute: F,
) -> R {
let mut overlay = sp_state_machine::OverlayedChanges::default();
let mut cache = Default::default();
let mut ext = Ext::<B>::new(&mut overlay, &mut cache, backend);
set_and_run_with_externalities(&mut ext, || execute())
}
fn host_storage_read(key: &[u8], value_out: &mut [u8], value_offset: u32) -> Option<u32> {
match with_externalities(|ext| ext.storage(key)) {
Some(value) => {