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