cumulus_primitives_timestamp/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
29
30use core::time::Duration;
31use cumulus_primitives_core::relay_chain::Slot;
32use sp_inherents::{Error, InherentData};
33
34pub use sp_timestamp::{InherentType, INHERENT_IDENTIFIER};
35
36pub struct InherentDataProvider {
41 relay_chain_slot: Slot,
42 relay_chain_slot_duration: Duration,
43}
44
45impl InherentDataProvider {
46 pub fn from_relay_chain_slot_and_duration(
48 relay_chain_slot: Slot,
49 relay_chain_slot_duration: Duration,
50 ) -> Self {
51 Self { relay_chain_slot, relay_chain_slot_duration }
52 }
53
54 pub fn create_inherent_data(&self) -> Result<InherentData, Error> {
56 let mut inherent_data = InherentData::new();
57 self.provide_inherent_data(&mut inherent_data).map(|_| inherent_data)
58 }
59
60 pub fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> {
62 let slot_duration_millis =
67 u64::try_from(self.relay_chain_slot_duration.as_millis()).unwrap_or(u64::MAX);
68 let next_slot = self.relay_chain_slot.saturating_add(1u64);
69 let data: InherentType = (*next_slot).saturating_mul(slot_duration_millis).into();
70
71 inherent_data.put_data(INHERENT_IDENTIFIER, &data)
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 fn timestamp_for(relay_chain_slot: u64, slot_duration: Duration) -> InherentType {
80 let inherent_data = InherentDataProvider::from_relay_chain_slot_and_duration(
81 Slot::from(relay_chain_slot),
82 slot_duration,
83 )
84 .create_inherent_data()
85 .expect("inherent data is created");
86
87 inherent_data
88 .get_data(&INHERENT_IDENTIFIER)
89 .expect("inherent data decodes")
90 .expect("inherent data is present")
91 }
92
93 #[test]
94 fn zero_slot_duration_is_a_zero_timestamp() {
95 assert_eq!(timestamp_for(100, Duration::ZERO), 0u64);
96 }
97
98 #[test]
99 fn timestamp_is_the_start_of_the_next_relay_chain_slot() {
100 assert_eq!(timestamp_for(100, Duration::from_millis(6_000)), 606_000u64);
101 }
102
103 #[test]
104 fn max_relay_chain_slot_does_not_overflow() {
105 assert_eq!(timestamp_for(u64::MAX, Duration::from_millis(6_000)), u64::MAX);
106 }
107
108 #[test]
109 fn huge_slot_duration_does_not_overflow() {
110 assert_eq!(timestamp_for(1, Duration::MAX), u64::MAX);
111 }
112
113 #[test]
114 fn slot_duration_above_u64_millis_does_not_truncate() {
115 let duration = Duration::new(18_446_744_073_709_551, 616_000_000);
117 assert_eq!(duration.as_millis(), u128::from(u64::MAX) + 1);
118 assert_eq!(timestamp_for(1, duration), u64::MAX);
119 }
120}