sc_consensus_manual_seal/consensus/
timestamp.rs1use crate::Error;
23use sc_client_api::{AuxStore, UsageProvider};
24use sp_api::ProvideRuntimeApi;
25use sp_blockchain::HeaderBackend;
26use sp_consensus_aura::{
27 sr25519::{AuthorityId, AuthoritySignature},
28 AuraApi,
29};
30use sp_consensus_babe::BabeApi;
31use sp_consensus_slots::{Slot, SlotDuration};
32use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier};
33use sp_runtime::traits::{Block as BlockT, Zero};
34use sp_timestamp::{InherentType, INHERENT_IDENTIFIER};
35use std::{
36 sync::{atomic, Arc},
37 time::SystemTime,
38};
39
40pub struct SlotTimestampProvider {
49 unix_millis: atomic::AtomicU64,
51 slot_duration: SlotDuration,
53}
54
55impl SlotTimestampProvider {
56 pub fn new_babe<B, C>(client: Arc<C>) -> Result<Self, Error>
58 where
59 B: BlockT,
60 C: AuxStore + HeaderBackend<B> + ProvideRuntimeApi<B> + UsageProvider<B>,
61 C::Api: BabeApi<B>,
62 {
63 let slot_duration = sc_consensus_babe::configuration(&*client)?.slot_duration();
64
65 let time = Self::with_header(&client, slot_duration, |header| {
66 let slot_number = *sc_consensus_babe::find_pre_digest::<B>(&header)
67 .map_err(|err| format!("{}", err))?
68 .slot();
69 Ok(slot_number)
70 })?;
71
72 Ok(Self { unix_millis: atomic::AtomicU64::new(time), slot_duration })
73 }
74
75 pub fn new_aura<B, C>(client: Arc<C>) -> Result<Self, Error>
77 where
78 B: BlockT,
79 C: AuxStore + HeaderBackend<B> + ProvideRuntimeApi<B> + UsageProvider<B>,
80 C::Api: AuraApi<B, AuthorityId>,
81 {
82 let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
83
84 let time = Self::with_header(&client, slot_duration, |header| {
85 let slot_number = *sc_consensus_aura::find_pre_digest::<B, AuthoritySignature>(&header)
86 .map_err(|err| format!("{}", err))?;
87 Ok(slot_number)
88 })?;
89
90 Ok(Self { unix_millis: atomic::AtomicU64::new(time), slot_duration })
91 }
92
93 fn with_header<F, C, B>(
94 client: &Arc<C>,
95 slot_duration: SlotDuration,
96 func: F,
97 ) -> Result<u64, Error>
98 where
99 B: BlockT,
100 C: AuxStore + HeaderBackend<B> + UsageProvider<B>,
101 F: Fn(B::Header) -> Result<u64, Error>,
102 {
103 let info = client.info();
104
105 let time = if info.best_number != Zero::zero() {
108 let header = client
109 .header(info.best_hash)?
110 .ok_or_else(|| "best header not found in the db!".to_string())?;
111 let slot = func(header)?;
112 (slot * slot_duration.as_millis() as u64) + slot_duration.as_millis() as u64
114 } else {
115 let now = SystemTime::now();
117 now.duration_since(SystemTime::UNIX_EPOCH)
118 .map_err(|err| Error::StringError(format!("{}", err)))?
119 .as_millis() as u64
120 };
121
122 Ok(time)
123 }
124
125 pub fn slot(&self) -> Slot {
127 Slot::from_timestamp(
128 self.unix_millis.load(atomic::Ordering::SeqCst).into(),
129 self.slot_duration,
130 )
131 }
132
133 pub fn timestamp(&self) -> sp_timestamp::Timestamp {
135 sp_timestamp::Timestamp::new(self.unix_millis.load(atomic::Ordering::SeqCst))
136 }
137}
138
139#[async_trait::async_trait]
140impl InherentDataProvider for SlotTimestampProvider {
141 async fn provide_inherent_data(
142 &self,
143 inherent_data: &mut InherentData,
144 ) -> Result<(), sp_inherents::Error> {
145 let new_time: InherentType = self
147 .unix_millis
148 .fetch_add(self.slot_duration.as_millis() as u64, atomic::Ordering::SeqCst)
149 .into();
150 inherent_data.put_data(INHERENT_IDENTIFIER, &new_time)?;
151 Ok(())
152 }
153
154 async fn try_handle_error(
155 &self,
156 _: &InherentIdentifier,
157 _: &[u8],
158 ) -> Option<Result<(), sp_inherents::Error>> {
159 None
160 }
161}