// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . //! Consensus extension module for BABE consensus. #![cfg_attr(not(feature = "std"), no_std)] #![forbid(unsafe_code)] pub use timestamp; use rstd::{result, prelude::*, marker::PhantomData}; use srml_support::{decl_storage, decl_module}; use timestamp::{OnTimestampSet, Trait}; use primitives::traits::{SaturatedConversion, Saturating}; #[cfg(feature = "std")] use timestamp::TimestampInherentData; use parity_codec::{Encode, Decode}; use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError}; #[cfg(feature = "std")] use inherents::{InherentDataProviders, ProvideInherentData}; #[cfg(feature = "std")] use serde::Serialize; /// The BABE inherent identifier. pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"babeslot"; /// The type of the BABE inherent. pub type InherentType = u64; /// Auxiliary trait to extract BABE inherent data. pub trait BabeInherentData { /// Get BABE inherent data. fn babe_inherent_data(&self) -> result::Result; /// Replace BABE inherent data. fn babe_replace_inherent_data(&mut self, new: InherentType); } impl BabeInherentData for InherentData { fn babe_inherent_data(&self) -> result::Result { self.get_data(&INHERENT_IDENTIFIER) .and_then(|r| r.ok_or_else(|| "BABE inherent data not found".into())) } fn babe_replace_inherent_data(&mut self, new: InherentType) { self.replace_data(INHERENT_IDENTIFIER, &new); } } /// Logs in this module. pub type Log = RawLog; /// Logs in this module. /// /// The type parameter distinguishes logs belonging to two different runtimes, /// which should not be mixed. #[cfg_attr(feature = "std", derive(Serialize, Debug))] #[derive(Encode, Decode, PartialEq, Eq, Clone)] pub enum RawLog { /// BABE inherent digests PreRuntime([u8; 4], Vec, PhantomData), } /// Provides the slot duration inherent data for BABE. #[cfg(feature = "std")] pub struct InherentDataProvider { slot_duration: u64, } #[cfg(feature = "std")] impl InherentDataProvider { pub fn new(slot_duration: u64) -> Self { Self { slot_duration } } } #[cfg(feature = "std")] impl ProvideInherentData for InherentDataProvider { fn on_register( &self, providers: &InherentDataProviders, ) -> result::Result<(), RuntimeString> { if !providers.has_provider(×tamp::INHERENT_IDENTIFIER) { // Add the timestamp inherent data provider, as we require it. providers.register_provider(timestamp::InherentDataProvider) } else { Ok(()) } } fn inherent_identifier(&self) -> &'static inherents::InherentIdentifier { &INHERENT_IDENTIFIER } fn provide_inherent_data( &self, inherent_data: &mut InherentData, ) -> result::Result<(), RuntimeString> { let timestamp = inherent_data.timestamp_inherent_data()?; let slot_num = timestamp / self.slot_duration; inherent_data.put_data(INHERENT_IDENTIFIER, &slot_num) } fn error_to_string(&self, error: &[u8]) -> Option { RuntimeString::decode(&mut &error[..]).map(Into::into) } } decl_storage! { trait Store for Module as Babe { // The last timestamp. LastTimestamp get(last): T::Moment; } } decl_module! { pub struct Module for enum Call where origin: T::Origin { } } impl Module { /// Determine the BABE slot duration based on the Timestamp module configuration. pub fn slot_duration() -> T::Moment { // we double the minimum block-period so each author can always propose within // the majority of their slot. >::minimum_period().saturating_mul(2.into()) } } impl OnTimestampSet for Module { fn on_timestamp_set(_moment: T::Moment) { } } impl ProvideInherent for Module { type Call = timestamp::Call; type Error = MakeFatalError; const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; fn create_inherent(_: &InherentData) -> Option { None } fn check_inherent(call: &Self::Call, data: &InherentData) -> result::Result<(), Self::Error> { let timestamp = match call { timestamp::Call::set(ref timestamp) => timestamp.clone(), _ => return Ok(()), }; let timestamp_based_slot = (timestamp / Self::slot_duration()).saturated_into::(); let seal_slot = data.babe_inherent_data()?; if timestamp_based_slot == seal_slot { Ok(()) } else { Err(RuntimeString::from("timestamp set in block doesn’t match slot in seal").into()) } } }