try_runtime_core/common/empty_block/inherents/custom_idps/
para_parachain.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Inherent data provider for the [cumulus parachin inherents](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/primitives/parachain-inherent/src/lib.rs)
19//! for empty block production on top of an existing externalities.
20
21use std::{ops::DerefMut, sync::Arc};
22
23use parity_scale_codec::{Decode, Encode};
24use polkadot_primitives::{BlockNumber, HeadData};
25use sp_consensus_babe::SlotDuration;
26use sp_core::twox_128;
27use sp_inherents::InherentIdentifier;
28use sp_runtime::traits::{Block as BlockT, HashingFor, NumberFor};
29use sp_state_machine::TestExternalities;
30use tokio::sync::Mutex;
31
32/// Get the para id if it exists
33pub fn get_para_id<B: BlockT>(ext: &mut TestExternalities<HashingFor<B>>) -> Option<u32> {
34    let para_id_key = [twox_128(b"ParachainInfo"), twox_128(b"ParachainId")].concat();
35
36    ext.execute_with(|| sp_io::storage::get(&para_id_key))
37        .and_then(|b| -> Option<u32> { Decode::decode(&mut &b[..]).ok() })
38}
39
40/// Get the last relay chain block number if it exists
41pub fn get_last_relay_chain_block_number<B: BlockT>(
42    ext: &mut TestExternalities<HashingFor<B>>,
43) -> Option<BlockNumber> {
44    let last_relay_chain_block_number_key = [
45        twox_128(b"ParachainSystem"),
46        twox_128(b"LastRelayChainBlockNumber"),
47    ]
48    .concat();
49
50    ext.execute_with(|| sp_io::storage::get(&last_relay_chain_block_number_key))
51        .and_then(|b| -> Option<NumberFor<B>> { Decode::decode(&mut &b[..]).ok() })
52        .map(|n| match n.try_into() {
53            Ok(block_number) => block_number,
54            Err(_) => {
55                panic!("Failed to convert relay chain block number")
56            }
57        })
58}
59
60/// Provides parachain-system pallet inherents.
61pub struct InherentDataProvider<B: BlockT> {
62    pub timestamp: sp_timestamp::Timestamp,
63    pub blocktime_millis: u64,
64    pub parent_header: B::Header,
65    pub ext_mutex: Arc<Mutex<TestExternalities<HashingFor<B>>>>,
66}
67
68#[async_trait::async_trait]
69impl<B: BlockT> sp_inherents::InherentDataProvider for InherentDataProvider<B> {
70    async fn provide_inherent_data(
71        &self,
72        inherent_data: &mut sp_inherents::InherentData,
73    ) -> Result<(), sp_inherents::Error> {
74        let mut ext_guard = self.ext_mutex.lock().await;
75        let ext = ext_guard.deref_mut();
76        let maybe_last_relay_chain_block_number = get_last_relay_chain_block_number::<B>(ext);
77        let maybe_para_id = get_para_id::<B>(ext);
78        let (last_relay_chain_block_number, para_id) =
79            match (maybe_last_relay_chain_block_number, maybe_para_id) {
80                (Some(last_relay_chain_block_number), Some(para_id)) => {
81                    (last_relay_chain_block_number, para_id)
82                }
83                _ => {
84                    log::debug!("Unable to provide para parachains inherent for this chain.");
85                    return Ok(());
86                }
87            };
88
89        let relay_chain_slot = cumulus_primitives_core::relay_chain::Slot::from_timestamp(
90            self.timestamp,
91            SlotDuration::from_millis(self.blocktime_millis),
92        )
93        .encode();
94
95        let additional_key_values: Vec<(Vec<u8>, Vec<u8>)> = vec![
96            // Insert relay chain slot to pass Aura check
97            // https://github.com/paritytech/polkadot-sdk/blob/ef114a422291b44f8973739ab7858a29a523e6a2/cumulus/pallets/aura-ext/src/consensus_hook.rs#L69
98            (
99                cumulus_primitives_core::relay_chain::well_known_keys::CURRENT_SLOT.to_vec(),
100                relay_chain_slot,
101            ),
102            // Insert para header info to pass para inherent check
103            // https://github.com/paritytech/polkadot-sdk/blob/17b56fae2d976a3df87f34076875de8c26da0355/cumulus/pallets/parachain-system/src/lib.rs#L1296
104            (
105                cumulus_primitives_core::relay_chain::well_known_keys::para_head(para_id.into()),
106                HeadData(self.parent_header.encode()).encode(),
107            ),
108        ];
109
110        cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider {
111            current_para_block: Default::default(),
112            current_para_block_head: Default::default(),
113            relay_offset: last_relay_chain_block_number + 1u32,
114            relay_blocks_per_para_block: Default::default(),
115            para_blocks_per_relay_epoch: Default::default(),
116            relay_randomness_config: (),
117            xcm_config: cumulus_client_parachain_inherent::MockXcmConfig::default(),
118            raw_downward_messages: Default::default(),
119            raw_horizontal_messages: Default::default(),
120            additional_key_values: Some(additional_key_values),
121            para_id: para_id.into(),
122        }
123        .provide_inherent_data(inherent_data)
124        .await
125        .expect("Failed to provide Para Parachain inherent data.");
126
127        Ok(())
128    }
129
130    async fn try_handle_error(
131        &self,
132        _: &InherentIdentifier,
133        _: &[u8],
134    ) -> Option<Result<(), sp_inherents::Error>> {
135        None
136    }
137}