try_runtime_core/common/empty_block/inherents/
providers.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//! Contains providers for inherents required for empty block production.
19
20use std::{sync::Arc, time::Duration};
21
22use parity_scale_codec::Encode;
23use sp_consensus_aura::{Slot, SlotDuration, AURA_ENGINE_ID};
24use sp_consensus_babe::{
25    digests::{PreDigest, SecondaryPlainPreDigest},
26    BABE_ENGINE_ID,
27};
28use sp_inherents::InherentData;
29use sp_runtime::{
30    traits::{Block as BlockT, HashingFor},
31    Digest, DigestItem,
32};
33use sp_state_machine::TestExternalities;
34use sp_std::prelude::*;
35use strum_macros::{Display, EnumIter};
36use tokio::sync::Mutex;
37
38use crate::common::empty_block::inherents::custom_idps;
39
40const RELAYCHAIN_BLOCKTIME_MS: u64 = 6000u64;
41
42/// Trait for providing the inherent data and digest items for block construction.
43pub trait InherentProvider<B: BlockT> {
44    type Err;
45
46    fn get_inherent_providers_and_pre_digest(
47        &self,
48        maybe_parent_info: Option<(InherentData, Digest)>,
49        parent_header: B::Header,
50        ext: Arc<Mutex<TestExternalities<HashingFor<B>>>>,
51        relay_parent_offset: u32,
52    ) -> InherentProviderResult<Self::Err>;
53}
54
55// Clippy asks that we abstract the return type because it's so long
56type InherentProviderResult<Err> =
57    Result<(Box<dyn sp_inherents::InherentDataProvider>, Vec<DigestItem>), Err>;
58
59/// Classes of [`InherentProvider`] avaliable.
60///
61/// Currently only Smart is implemented. New implementations may be added if Smart is not suitable
62/// for some edge cases.
63#[derive(Debug, Clone, EnumIter, Display, Copy)]
64pub enum ProviderVariant {
65    /// Smart chain varient will automatically adjust provided inherents based on the given
66    /// externalities.
67    ///
68    /// The blocktime is provided in milliseconds.
69    Smart(core::time::Duration),
70}
71
72impl<B: BlockT> InherentProvider<B> for ProviderVariant {
73    type Err = String;
74
75    fn get_inherent_providers_and_pre_digest(
76        &self,
77        maybe_parent_info: Option<(InherentData, Digest)>,
78        parent_header: B::Header,
79        ext: Arc<Mutex<TestExternalities<HashingFor<B>>>>,
80        relay_parent_offset: u32,
81    ) -> InherentProviderResult<Self::Err> {
82        match *self {
83            ProviderVariant::Smart(blocktime) => {
84                <SmartInherentProvider as InherentProvider<B>>::get_inherent_providers_and_pre_digest(&SmartInherentProvider {
85                     blocktime,
86                 }, maybe_parent_info, parent_header, ext, relay_parent_offset)
87            }
88        }
89    }
90}
91
92/// Attempts to provide inherents in a fashion that works for as many chains as possible.
93///
94/// It is currently tested for
95/// - Polkadot-based relay chains
96/// - Polkadot-ecosystem system parachains
97///
98/// If it does not work for your Substrate-based chain, [please open an issue](https://github.com/paritytech/try-runtime-cli/issues)
99/// and we will look into supporting it.
100struct SmartInherentProvider {
101    blocktime: Duration,
102}
103
104impl<B: BlockT> InherentProvider<B> for SmartInherentProvider {
105    type Err = String;
106
107    fn get_inherent_providers_and_pre_digest(
108        &self,
109        maybe_parent_info: Option<(InherentData, Digest)>,
110        parent_header: B::Header,
111        ext: Arc<Mutex<TestExternalities<HashingFor<B>>>>,
112        relay_parent_offset: u32,
113    ) -> InherentProviderResult<Self::Err> {
114        let timestamp_idp = custom_idps::timestamp::InherentDataProvider {
115            blocktime_millis: self.blocktime.as_millis() as u64,
116            maybe_parent_info,
117        };
118        let para_parachain_idp = custom_idps::para_parachain::InherentDataProvider::<B> {
119            blocktime_millis: RELAYCHAIN_BLOCKTIME_MS,
120            parent_header: parent_header.clone(),
121            timestamp: timestamp_idp.timestamp(),
122            ext_mutex: ext,
123            relay_parent_offset,
124        };
125        let relay_parachain_data_idp =
126            custom_idps::relay_parachains::InherentDataProvider::<B>::new(parent_header);
127
128        let slot = Slot::from_timestamp(
129            timestamp_idp.timestamp(),
130            SlotDuration::from_millis(self.blocktime.as_millis() as u64),
131        );
132        let digest = vec![
133            DigestItem::PreRuntime(
134                BABE_ENGINE_ID,
135                PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
136                    slot,
137                    authority_index: 0,
138                })
139                .encode(),
140            ),
141            DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode()),
142        ];
143
144        Ok((
145            Box::new((timestamp_idp, para_parachain_idp, relay_parachain_data_idp)),
146            digest,
147        ))
148    }
149}