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    ) -> InherentProviderResult<Self::Err>;
52}
53
54// Clippy asks that we abstract the return type because it's so long
55type InherentProviderResult<Err> =
56    Result<(Box<dyn sp_inherents::InherentDataProvider>, Vec<DigestItem>), Err>;
57
58/// Classes of [`InherentProvider`] avaliable.
59///
60/// Currently only Smart is implemented. New implementations may be added if Smart is not suitable
61/// for some edge cases.
62#[derive(Debug, Clone, EnumIter, Display, Copy)]
63pub enum ProviderVariant {
64    /// Smart chain varient will automatically adjust provided inherents based on the given
65    /// externalities.
66    ///
67    /// The blocktime is provided in milliseconds.
68    Smart(core::time::Duration),
69}
70
71impl<B: BlockT> InherentProvider<B> for ProviderVariant {
72    type Err = String;
73
74    fn get_inherent_providers_and_pre_digest(
75        &self,
76        maybe_parent_info: Option<(InherentData, Digest)>,
77        parent_header: B::Header,
78        ext: Arc<Mutex<TestExternalities<HashingFor<B>>>>,
79    ) -> InherentProviderResult<Self::Err> {
80        match *self {
81            ProviderVariant::Smart(blocktime) => {
82                <SmartInherentProvider as InherentProvider<B>>::get_inherent_providers_and_pre_digest(&SmartInherentProvider {
83                     blocktime,
84                 }, maybe_parent_info, parent_header, ext)
85            }
86        }
87    }
88}
89
90/// Attempts to provide inherents in a fashion that works for as many chains as possible.
91///
92/// It is currently tested for
93/// - Polkadot-based relay chains
94/// - Polkadot-ecosystem system parachains
95///
96/// If it does not work for your Substrate-based chain, [please open an issue](https://github.com/paritytech/try-runtime-cli/issues)
97/// and we will look into supporting it.
98struct SmartInherentProvider {
99    blocktime: Duration,
100}
101
102impl<B: BlockT> InherentProvider<B> for SmartInherentProvider {
103    type Err = String;
104
105    fn get_inherent_providers_and_pre_digest(
106        &self,
107        maybe_parent_info: Option<(InherentData, Digest)>,
108        parent_header: B::Header,
109        ext: Arc<Mutex<TestExternalities<HashingFor<B>>>>,
110    ) -> InherentProviderResult<Self::Err> {
111        let timestamp_idp = custom_idps::timestamp::InherentDataProvider {
112            blocktime_millis: self.blocktime.as_millis() as u64,
113            maybe_parent_info,
114        };
115        let para_parachain_idp = custom_idps::para_parachain::InherentDataProvider::<B> {
116            blocktime_millis: RELAYCHAIN_BLOCKTIME_MS,
117            parent_header: parent_header.clone(),
118            timestamp: timestamp_idp.timestamp(),
119            ext_mutex: ext,
120        };
121        let relay_parachain_data_idp =
122            custom_idps::relay_parachains::InherentDataProvider::<B>::new(parent_header);
123
124        let slot = Slot::from_timestamp(
125            timestamp_idp.timestamp(),
126            SlotDuration::from_millis(self.blocktime.as_millis() as u64),
127        );
128        let digest = vec![
129            DigestItem::PreRuntime(
130                BABE_ENGINE_ID,
131                PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
132                    slot,
133                    authority_index: 0,
134                })
135                .encode(),
136            ),
137            DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode()),
138        ];
139
140        Ok((
141            Box::new((timestamp_idp, para_parachain_idp, relay_parachain_data_idp)),
142            digest,
143        ))
144    }
145}