1use super::{InherentDataProviderExt, Slot, LOG_TARGET};
24use sp_consensus::{SelectChain, SyncOracle};
25use sp_inherents::{CreateInherentDataProviders, InherentDataProvider};
26use sp_runtime::traits::{Block as BlockT, HashingFor, Header as HeaderT};
27use sp_trie::recorder::Recorder;
28
29use futures_timer::Delay;
30use std::time::{Duration, Instant};
31
32pub fn duration_now() -> Duration {
34 use std::time::SystemTime;
35 let now = SystemTime::now();
36 now.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_else(|e| {
37 panic!("Current time {:?} is before unix epoch. Something is wrong: {:?}", now, e)
38 })
39}
40
41pub fn time_until_next_slot(slot_duration: Duration) -> Duration {
43 let now = duration_now().as_millis();
44
45 let next_slot = (now + slot_duration.as_millis()) / slot_duration.as_millis();
46 let remaining_millis = next_slot * slot_duration.as_millis() - now;
47 Duration::from_millis(remaining_millis as u64)
48}
49
50pub struct SlotInfo<B: BlockT> {
52 pub slot: Slot,
54 pub ends_at: Instant,
56 pub create_inherent_data: Box<dyn InherentDataProvider>,
58 pub duration: Duration,
60 pub chain_head: B::Header,
62 pub block_size_limit: Option<usize>,
66 pub storage_proof_recorder: Option<Recorder<HashingFor<B>>>,
68}
69
70impl<B: BlockT> SlotInfo<B> {
71 pub fn new(
75 slot: Slot,
76 create_inherent_data: Box<dyn InherentDataProvider>,
77 duration: Duration,
78 chain_head: B::Header,
79 block_size_limit: Option<usize>,
80 ) -> Self {
81 Self {
82 slot,
83 create_inherent_data,
84 duration,
85 chain_head,
86 block_size_limit,
87 ends_at: Instant::now() + time_until_next_slot(duration),
88 storage_proof_recorder: None,
89 }
90 }
91
92 pub fn with_storage_proof_recorder(
96 slot: Slot,
97 create_inherent_data: Box<dyn InherentDataProvider>,
98 duration: Duration,
99 chain_head: B::Header,
100 block_size_limit: Option<usize>,
101 storage_proof_recorder: Recorder<HashingFor<B>>,
102 ) -> Self {
103 Self {
104 slot,
105 create_inherent_data,
106 duration,
107 chain_head,
108 block_size_limit,
109 ends_at: Instant::now() + time_until_next_slot(duration),
110 storage_proof_recorder: Some(storage_proof_recorder),
111 }
112 }
113}
114
115pub(crate) struct Slots<Block, SC, IDP, SO> {
117 last_slot: Slot,
118 slot_duration: Duration,
119 until_next_slot: Option<Delay>,
120 create_inherent_data_providers: IDP,
121 select_chain: SC,
122 sync_oracle: SO,
123 _phantom: std::marker::PhantomData<Block>,
124}
125
126impl<Block, SC, IDP, SO> Slots<Block, SC, IDP, SO> {
127 pub fn new(
129 slot_duration: Duration,
130 create_inherent_data_providers: IDP,
131 select_chain: SC,
132 sync_oracle: SO,
133 ) -> Self {
134 Slots {
135 last_slot: 0.into(),
136 slot_duration,
137 until_next_slot: None,
138 create_inherent_data_providers,
139 select_chain,
140 sync_oracle,
141 _phantom: Default::default(),
142 }
143 }
144}
145
146impl<Block, SC, IDP, SO> Slots<Block, SC, IDP, SO>
147where
148 Block: BlockT,
149 SC: SelectChain<Block>,
150 IDP: CreateInherentDataProviders<Block, ()> + 'static,
151 IDP::InherentDataProviders: crate::InherentDataProviderExt,
152 SO: SyncOracle,
153{
154 pub async fn next_slot(&mut self) -> SlotInfo<Block> {
156 loop {
157 self.until_next_slot
159 .take()
160 .unwrap_or_else(|| {
161 let wait_dur = time_until_next_slot(self.slot_duration);
163 Delay::new(wait_dur)
164 })
165 .await;
166
167 let wait_dur = time_until_next_slot(self.slot_duration);
169 self.until_next_slot = Some(Delay::new(wait_dur));
170
171 if self.sync_oracle.is_major_syncing() {
172 log::debug!(target: LOG_TARGET, "Skipping slot: major sync is in progress.");
173 continue;
174 }
175
176 let chain_head = match self.select_chain.best_chain().await {
177 Ok(x) => x,
178 Err(e) => {
179 log::warn!(
180 target: LOG_TARGET,
181 "Unable to author block in slot. No best block header: {}",
182 e,
183 );
184 continue
186 },
187 };
188
189 let inherent_data_providers = match self
190 .create_inherent_data_providers
191 .create_inherent_data_providers(chain_head.hash(), ())
192 .await
193 {
194 Ok(x) => x,
195 Err(e) => {
196 log::warn!(
197 target: LOG_TARGET,
198 "Unable to author block in slot. Failure creating inherent data provider: {}",
199 e,
200 );
201 continue
203 },
204 };
205
206 let slot = inherent_data_providers.slot();
207
208 if slot > self.last_slot {
210 self.last_slot = slot;
211
212 break SlotInfo::new(
213 slot,
214 Box::new(inherent_data_providers),
215 self.slot_duration,
216 chain_head,
217 None,
218 )
219 }
220 }
221 }
222}