// This file is part of Substrate. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::BlockT; use parity_scale_codec::Encode; use sc_cli::Result; use sp_consensus_aura::{Slot, SlotDuration, AURA_ENGINE_ID}; use sp_consensus_babe::{ digests::{PreDigest, SecondaryPlainPreDigest}, BABE_ENGINE_ID, }; use sp_inherents::{InherentData, InherentDataProvider}; use sp_runtime::{Digest, DigestItem}; use sp_timestamp::TimestampInherentData; /// Something that can create inherent data providers and pre-runtime digest. /// /// It is possible for the caller to provide custom arguments to the callee by setting the /// `ExtraArgs` generic parameter. /// /// This module already provides some convenience implementation of this trait for closures. So, it /// should not be required to implement it directly. #[async_trait::async_trait] pub trait BlockBuildingInfoProvider { type InherentDataProviders: InherentDataProvider; async fn get_inherent_providers_and_pre_digest( &self, parent_hash: Block::Hash, extra_args: ExtraArgs, ) -> Result<(Self::InherentDataProviders, Vec)>; } #[async_trait::async_trait] impl BlockBuildingInfoProvider for F where Block: BlockT, F: Fn(Block::Hash, ExtraArgs) -> Fut + Sync + Send, Fut: std::future::Future)>> + Send + 'static, IDP: InherentDataProvider + 'static, ExtraArgs: Send + 'static, { type InherentDataProviders = IDP; async fn get_inherent_providers_and_pre_digest( &self, parent: Block::Hash, extra_args: ExtraArgs, ) -> Result<(Self::InherentDataProviders, Vec)> { (*self)(parent, extra_args).await } } /// Provides [`BlockBuildingInfoProvider`] implementation for chains that include timestamp inherent /// and use Aura for a block production. /// /// It depends only on the expected block production frequency, i.e. `blocktime_millis`. pub fn timestamp_with_aura_info( blocktime_millis: u64, ) -> impl BlockBuildingInfoProvider> { move |_, maybe_prev_info: Option<(InherentData, Digest)>| async move { let timestamp_idp = match maybe_prev_info { Some((inherent_data, _)) => sp_timestamp::InherentDataProvider::new( inherent_data.timestamp_inherent_data().unwrap().unwrap() + blocktime_millis, ), None => sp_timestamp::InherentDataProvider::from_system_time(), }; let slot = Slot::from_timestamp(*timestamp_idp, SlotDuration::from_millis(blocktime_millis)); let digest = vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())]; Ok((timestamp_idp, digest)) } } /// Provides [`BlockBuildingInfoProvider`] implementation for chains that include timestamp inherent /// and use Babe for a block production. /// /// It depends only on the expected block production frequency, i.e. `blocktime_millis`. pub fn timestamp_with_babe_info( blocktime_millis: u64, ) -> impl BlockBuildingInfoProvider> { move |_, maybe_prev_info: Option<(InherentData, Digest)>| async move { let timestamp_idp = match maybe_prev_info { Some((inherent_data, _)) => sp_timestamp::InherentDataProvider::new( inherent_data.timestamp_inherent_data().unwrap().unwrap() + blocktime_millis, ), None => sp_timestamp::InherentDataProvider::from_system_time(), }; let slot = Slot::from_timestamp(*timestamp_idp, SlotDuration::from_millis(blocktime_millis)); let slot_idp = sp_consensus_babe::inherents::InherentDataProvider::new(slot); let digest = vec![DigestItem::PreRuntime( BABE_ENGINE_ID, PreDigest::SecondaryPlain(SecondaryPlainPreDigest { slot, authority_index: 0 }) .encode(), )]; Ok(((slot_idp, timestamp_idp), digest)) } } /// Provides [`BlockBuildingInfoProvider`] implementation for chains that use: /// - timestamp inherent, /// - Babe for a block production (inherent + digest), /// - uncles inherent, /// - storage proof inherent /// /// It depends only on the expected block production frequency, i.e. `blocktime_millis`. pub fn substrate_info( blocktime_millis: u64, ) -> impl BlockBuildingInfoProvider> { move |_, maybe_prev_info: Option<(InherentData, Digest)>| async move { let timestamp_idp = match maybe_prev_info { Some((inherent_data, _)) => sp_timestamp::InherentDataProvider::new( inherent_data.timestamp_inherent_data().unwrap().unwrap() + blocktime_millis, ), None => sp_timestamp::InherentDataProvider::from_system_time(), }; let slot = Slot::from_timestamp(*timestamp_idp, SlotDuration::from_millis(blocktime_millis)); let slot_idp = sp_consensus_babe::inherents::InherentDataProvider::new(slot); let storage_proof_idp = sp_transaction_storage_proof::InherentDataProvider::new(None); let digest = vec![DigestItem::PreRuntime( BABE_ENGINE_ID, PreDigest::SecondaryPlain(SecondaryPlainPreDigest { slot, authority_index: 0 }) .encode(), )]; Ok(((slot_idp, timestamp_idp, storage_proof_idp), digest)) } }