diff --git a/Cargo.toml b/Cargo.toml index 7adf779..e04f654 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "init4-bin-base" description = "Internal utilities for binaries produced by the init4 team" keywords = ["init4", "bin", "base"] -version = "0.7.0" +version = "0.7.1" edition = "2021" rust-version = "1.81" authors = ["init4", "James Prestwich"] diff --git a/src/utils/calc.rs b/src/utils/calc.rs index 3d739fa..52faf84 100644 --- a/src/utils/calc.rs +++ b/src/utils/calc.rs @@ -244,6 +244,33 @@ impl SlotCalculator { pub fn current_point_within_slot(&self) -> Option { self.point_within_slot(chrono::Utc::now().timestamp() as u64) } + + /// Calculates the slot that starts at the given timestamp. + /// Returns `None` if the timestamp is not a slot boundary. + /// Returns `None` if the timestamp is before the chain's start timestamp. + pub fn slot_starting_at(&self, timestamp: u64) -> Option { + let elapsed = timestamp.checked_sub(self.start_timestamp)?; + + if elapsed % self.slot_duration != 0 { + return None; + } + + self.slot_containing(timestamp) + } + + /// Calculates the slot that ends at the given timestamp. + /// Returns `None` if the timestamp is not a slot boundary. + /// Returns `None` if the timestamp is before the chain's start timestamp. + pub fn slot_ending_at(&self, timestamp: u64) -> Option { + let elapsed = timestamp.checked_sub(self.start_timestamp)?; + + if elapsed % self.slot_duration != 0 { + return None; + } + + self.slot_containing(timestamp) + .and_then(|slot| slot.checked_sub(1)) + } } #[cfg(test)] @@ -261,14 +288,22 @@ mod tests { #[test] fn test_basic_slot_calculations() { let calculator = SlotCalculator::new(12, 0, 12); + assert_eq!(calculator.slot_ending_at(0), None); assert_eq!(calculator.slot_containing(0), None); assert_eq!(calculator.slot_containing(1), None); assert_eq!(calculator.slot_containing(11), None); + assert_eq!(calculator.slot_ending_at(11), None); + assert_eq!(calculator.slot_ending_at(12), Some(0)); + assert_eq!(calculator.slot_starting_at(12), Some(1)); assert_eq!(calculator.slot_containing(12), Some(1)); assert_eq!(calculator.slot_containing(13), Some(1)); + assert_eq!(calculator.slot_starting_at(13), None); assert_eq!(calculator.slot_containing(23), Some(1)); + assert_eq!(calculator.slot_ending_at(23), None); + assert_eq!(calculator.slot_ending_at(24), Some(1)); + assert_eq!(calculator.slot_starting_at(24), Some(2)); assert_eq!(calculator.slot_containing(24), Some(2)); assert_eq!(calculator.slot_containing(25), Some(2)); assert_eq!(calculator.slot_containing(35), Some(2));