From 4ebdd70409dd646b7d296b105c6f479b53dd4956 Mon Sep 17 00:00:00 2001 From: evalir Date: Thu, 10 Jul 2025 19:03:14 +0200 Subject: [PATCH 1/4] feat(utils): add `slot_starting_at` / `slot_ending_at` fns to the calculator These functions can calculate the slot that begins or ends at a given timestamp, as LONG as it's a slot boundary. Else, the ywill return `None`. --- src/utils/calc.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/utils/calc.rs b/src/utils/calc.rs index 3d739fa..85395a3 100644 --- a/src/utils/calc.rs +++ b/src/utils/calc.rs @@ -244,6 +244,30 @@ 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. + /// If given a timestamp that is NOT a slot boundary, it will return + /// `None`. + pub const fn slot_starting_at(&self, timestamp: u64) -> Option { + if timestamp % self.slot_duration != 0 { + return None; + } + + self.slot_containing(timestamp) + } + + /// Calculates the slot that ends at the given timestamp. + /// If given a timestamp that is NOT a slot boundary, it will return + /// `None`. + pub fn slot_ending_at(&self, timestamp: u64) -> Option { + if timestamp % self.slot_duration != 0 { + return None; + } + + self.slot_containing(timestamp) + .and_then(|slot| slot.checked_sub(1)) + .and_then(|slot| if slot == 0 { None } else { Some(slot) }) + } } #[cfg(test)] @@ -265,10 +289,16 @@ mod tests { assert_eq!(calculator.slot_containing(1), None); assert_eq!(calculator.slot_containing(11), None); + assert_eq!(calculator.slot_ending_at(12), None); + 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)); From 6bfddd23c4ad830c6f6a8a10b0da092c790f7b7a Mon Sep 17 00:00:00 2001 From: evalir Date: Thu, 10 Jul 2025 19:05:24 +0200 Subject: [PATCH 2/4] chore: v bump to 0.8.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7adf779..7dfbc44 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.8.0" edition = "2021" rust-version = "1.81" authors = ["init4", "James Prestwich"] From 580f10536223be82f60dbcfe11d1468f2c6951e5 Mon Sep 17 00:00:00 2001 From: evalir Date: Thu, 10 Jul 2025 20:08:37 +0200 Subject: [PATCH 3/4] chore: docs, fixes --- Cargo.toml | 2 +- src/utils/calc.rs | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7dfbc44..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.8.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 85395a3..6f3eccc 100644 --- a/src/utils/calc.rs +++ b/src/utils/calc.rs @@ -246,10 +246,14 @@ impl SlotCalculator { } /// Calculates the slot that starts at the given timestamp. - /// If given a timestamp that is NOT a slot boundary, it will return - /// `None`. + /// Returns `None` if the timestamp is not a slot boundary. + /// Returns `None` if the timestamp is before the chain's start timestamp. pub const fn slot_starting_at(&self, timestamp: u64) -> Option { - if timestamp % self.slot_duration != 0 { + let Some(elapsed) = timestamp.checked_sub(self.start_timestamp) else { + return None; + }; + + if elapsed % self.slot_duration != 0 { return None; } @@ -257,16 +261,19 @@ impl SlotCalculator { } /// Calculates the slot that ends at the given timestamp. - /// If given a timestamp that is NOT a slot boundary, it will return - /// `None`. + /// 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 { - if timestamp % self.slot_duration != 0 { + let Some(elapsed) = timestamp.checked_sub(self.start_timestamp) else { + return None; + }; + + if elapsed % self.slot_duration != 0 { return None; } self.slot_containing(timestamp) .and_then(|slot| slot.checked_sub(1)) - .and_then(|slot| if slot == 0 { None } else { Some(slot) }) } } @@ -285,11 +292,13 @@ 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(12), 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)); From 9f690b8ffc3ba59d5f6eb7de6da000643ea6c9dc Mon Sep 17 00:00:00 2001 From: evalir Date: Thu, 10 Jul 2025 20:17:39 +0200 Subject: [PATCH 4/4] lmao --- src/utils/calc.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/utils/calc.rs b/src/utils/calc.rs index 6f3eccc..52faf84 100644 --- a/src/utils/calc.rs +++ b/src/utils/calc.rs @@ -248,10 +248,8 @@ impl SlotCalculator { /// 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 const fn slot_starting_at(&self, timestamp: u64) -> Option { - let Some(elapsed) = timestamp.checked_sub(self.start_timestamp) else { - return None; - }; + 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; @@ -264,9 +262,7 @@ impl SlotCalculator { /// 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 Some(elapsed) = timestamp.checked_sub(self.start_timestamp) else { - return None; - }; + let elapsed = timestamp.checked_sub(self.start_timestamp)?; if elapsed % self.slot_duration != 0 { return None;