sc_consensus_slots/
slots.rs1use super::{InherentDataProviderExt, Slot, LOG_TARGET};
24use sp_consensus::{SelectChain, SyncOracle};
25use sp_inherents::{CreateInherentDataProviders, InherentDataProvider};
26use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
27
28use futures_timer::Delay;
29use std::time::{Duration, Instant};
30
31pub fn duration_now() -> Duration {
33 use std::time::SystemTime;
34 let now = SystemTime::now();
35 now.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_else(|e| {
36 panic!("Current time {:?} is before unix epoch. Something is wrong: {:?}", now, e)
37 })
38}
39
40pub fn time_until_next_slot(slot_duration: Duration) -> Duration {
42 let now = duration_now().as_millis();
43
44 let next_slot = (now + slot_duration.as_millis()) / slot_duration.as_millis();
45 let remaining_millis = next_slot * slot_duration.as_millis() - now;
46 Duration::from_millis(remaining_millis as u64)
47}
48
49pub struct SlotInfo<B: BlockT> {
51 pub slot: Slot,
53 pub ends_at: Instant,
55 pub create_inherent_data: Box<dyn InherentDataProvider>,
57 pub duration: Duration,
59 pub chain_head: B::Header,
61 pub block_size_limit: Option<usize>,
65}
66
67impl<B: BlockT> SlotInfo<B> {
68 pub fn new(
72 slot: Slot,
73 create_inherent_data: Box<dyn InherentDataProvider>,
74 duration: Duration,
75 chain_head: B::Header,
76 block_size_limit: Option<usize>,
77 ) -> Self {
78 Self {
79 slot,
80 create_inherent_data,
81 duration,
82 chain_head,
83 block_size_limit,
84 ends_at: Instant::now() + time_until_next_slot(duration),
85 }
86 }
87}
88
89pub(crate) struct Slots<Block, SC, IDP, SO> {
91 last_slot: Slot,
92 slot_duration: Duration,
93 until_next_slot: Option<Delay>,
94 create_inherent_data_providers: IDP,
95 select_chain: SC,
96 sync_oracle: SO,
97 _phantom: std::marker::PhantomData<Block>,
98}
99
100impl<Block, SC, IDP, SO> Slots<Block, SC, IDP, SO> {
101 pub fn new(
103 slot_duration: Duration,
104 create_inherent_data_providers: IDP,
105 select_chain: SC,
106 sync_oracle: SO,
107 ) -> Self {
108 Slots {
109 last_slot: 0.into(),
110 slot_duration,
111 until_next_slot: None,
112 create_inherent_data_providers,
113 select_chain,
114 sync_oracle,
115 _phantom: Default::default(),
116 }
117 }
118}
119
120impl<Block, SC, IDP, SO> Slots<Block, SC, IDP, SO>
121where
122 Block: BlockT,
123 SC: SelectChain<Block>,
124 IDP: CreateInherentDataProviders<Block, ()> + 'static,
125 IDP::InherentDataProviders: crate::InherentDataProviderExt,
126 SO: SyncOracle,
127{
128 pub async fn next_slot(&mut self) -> SlotInfo<Block> {
130 loop {
131 self.until_next_slot
133 .take()
134 .unwrap_or_else(|| {
135 let wait_dur = time_until_next_slot(self.slot_duration);
137 Delay::new(wait_dur)
138 })
139 .await;
140
141 let wait_dur = time_until_next_slot(self.slot_duration);
143 self.until_next_slot = Some(Delay::new(wait_dur));
144
145 if self.sync_oracle.is_major_syncing() {
146 log::debug!(target: LOG_TARGET, "Skipping slot: major sync is in progress.");
147 continue;
148 }
149
150 let chain_head = match self.select_chain.best_chain().await {
151 Ok(x) => x,
152 Err(e) => {
153 log::warn!(
154 target: LOG_TARGET,
155 "Unable to author block in slot. No best block header: {}",
156 e,
157 );
158 continue
160 },
161 };
162
163 let inherent_data_providers = match self
164 .create_inherent_data_providers
165 .create_inherent_data_providers(chain_head.hash(), ())
166 .await
167 {
168 Ok(x) => x,
169 Err(e) => {
170 log::warn!(
171 target: LOG_TARGET,
172 "Unable to author block in slot. Failure creating inherent data provider: {}",
173 e,
174 );
175 continue
177 },
178 };
179
180 let slot = inherent_data_providers.slot();
181
182 if slot > self.last_slot {
184 self.last_slot = slot;
185
186 break SlotInfo::new(
187 slot,
188 Box::new(inherent_data_providers),
189 self.slot_duration,
190 chain_head,
191 None,
192 )
193 }
194 }
195 }
196}