use crate::header;
use core::{num::NonZero, time::Duration};
pub struct Config<'a, TLocAuth> {
pub now_from_unix_epoch: Duration,
pub slot_duration: NonZero<u64>,
pub current_authorities: header::AuraAuthoritiesIter<'a>,
pub local_authorities: TLocAuth,
}
pub fn next_slot_claim<'a>(
config: Config<'a, impl Iterator<Item = &'a [u8; 32]>>,
) -> Option<SlotClaim> {
let num_current_authorities = config.current_authorities.clone().count();
let current_slot = u64::try_from(
config.now_from_unix_epoch.as_millis() / u128::from(config.slot_duration.get()),
)
.unwrap();
let current_slot_index =
usize::try_from(current_slot.checked_rem(u64::try_from(num_current_authorities).unwrap())?)
.unwrap();
debug_assert!(current_slot_index < num_current_authorities);
let mut claim = None;
for (pub_key_index, local_pub_key) in config.local_authorities.enumerate() {
let mut index = match config
.current_authorities
.clone()
.position(|pk| pk.public_key == local_pub_key)
{
Some(idx) => idx,
None => continue,
};
if index < current_slot_index {
index += num_current_authorities;
}
debug_assert!(index >= current_slot_index);
let claimable_slot = current_slot + u64::try_from(index - current_slot_index).unwrap();
match claim {
Some((s, _)) if s <= claimable_slot => {}
_ => claim = Some((claimable_slot, pub_key_index)),
}
}
if let Some((slot_number, local_authorities_index)) = claim {
let slot_start_from_unix_epoch =
Duration::from_millis(slot_number.checked_mul(config.slot_duration.get()).unwrap());
let slot_end_from_unix_epoch =
slot_start_from_unix_epoch + Duration::from_secs(config.slot_duration.get());
debug_assert!(slot_end_from_unix_epoch > config.now_from_unix_epoch);
Some(SlotClaim {
slot_start_from_unix_epoch,
slot_end_from_unix_epoch,
slot_number,
local_authorities_index,
})
} else {
None
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct SlotClaim {
pub slot_start_from_unix_epoch: Duration,
pub slot_end_from_unix_epoch: Duration,
pub slot_number: u64,
pub local_authorities_index: usize,
}