diff --git a/blockchain-source/src/cardano/byron.rs b/blockchain-source/src/cardano/byron.rs index 4b053cd..35515ab 100644 --- a/blockchain-source/src/cardano/byron.rs +++ b/blockchain-source/src/cardano/byron.rs @@ -10,7 +10,7 @@ //! //! This doesn't implement full support for the first point, we only parse what's needed to compute //! the hash, parent, height, and epoch-slot of epoch boundary blocks. -use super::time::epoch_slot_to_absolute; +use super::time::epoch_slot_to_absolute_byron; use anyhow::Context; use cardano_sdk::chain::{ byron::{self, ChainDifficulty}, @@ -115,12 +115,14 @@ impl ByronHeader { pub(super) fn slot_number(&self) -> SlotNumber { SlotNumber::new(match self { - ByronHeader::ByronBoundary(header) => epoch_slot_to_absolute(header.consensus.epoch, 0), + ByronHeader::ByronBoundary(header) => { + epoch_slot_to_absolute_byron(header.consensus.epoch, 0) + } ByronHeader::Byron(header) => { let slot = header.consensus.slot_id.slot_id.into(); let epoch = header.consensus.slot_id.epoch; - epoch_slot_to_absolute(epoch, slot) + epoch_slot_to_absolute_byron(epoch, slot) } }) } diff --git a/blockchain-source/src/cardano/time.rs b/blockchain-source/src/cardano/time.rs index 3008507..b3abe24 100644 --- a/blockchain-source/src/cardano/time.rs +++ b/blockchain-source/src/cardano/time.rs @@ -7,6 +7,7 @@ pub struct Era { pub start_epoch: u64, pub known_time: u64, pub slot_length: u64, + pub epoch_length_seconds: u64, } impl Era { @@ -15,6 +16,7 @@ impl Era { start_epoch: 208, known_time: 1596059091, slot_length: 1, + epoch_length_seconds: 432000, }; pub const SHELLEY_TESTNET: Self = Self { @@ -22,6 +24,7 @@ impl Era { start_epoch: 74, known_time: 1595967616, slot_length: 1, + epoch_length_seconds: 432000, }; pub const SHELLEY_PREPROD: Self = Self { @@ -29,13 +32,15 @@ impl Era { start_epoch: 4, known_time: 1655769600, slot_length: 1, + epoch_length_seconds: 432000, }; pub const SHELLEY_PREVIEW: Self = Self { first_slot: 0, start_epoch: 0, - known_time: 1660003200, + known_time: 1666656000, slot_length: 1, + epoch_length_seconds: 86400, }; pub const fn compute_timestamp(&self, slot: u64) -> u64 { @@ -45,12 +50,17 @@ impl Era { pub fn absolute_slot_to_epoch(&self, slot: u64) -> Option { slot.checked_sub(self.first_slot) .map(|slot_relative_to_era| { - self.start_epoch + slot_relative_to_era / EPOCH_LENGTH_IN_SECONDS + self.start_epoch + slot_relative_to_era / self.epoch_length_seconds }) } + + pub fn absolute_slot_to_relative(&self, slot: u64) -> Option { + slot.checked_sub(self.first_slot) + .map(|slot_relative_to_era| slot_relative_to_era % self.epoch_length_seconds) + } } -pub const fn epoch_slot_to_absolute(epoch: u64, epoch_slot: u64) -> u64 { +pub const fn epoch_slot_to_absolute_byron(epoch: u64, epoch_slot: u64) -> u64 { let slots_per_epoch = EPOCH_LENGTH_IN_SECONDS / BYRON_SLOT_DURATION; epoch * slots_per_epoch + epoch_slot } @@ -68,19 +78,31 @@ mod tests { assert_eq!(Some(208), era.absolute_slot_to_epoch(4492840)); assert_eq!( Some(208), - era.absolute_slot_to_epoch(era.first_slot + EPOCH_LENGTH_IN_SECONDS - 1) + era.absolute_slot_to_epoch(era.first_slot + era.epoch_length_seconds - 1) ); assert_eq!( Some(209), - era.absolute_slot_to_epoch(era.first_slot + EPOCH_LENGTH_IN_SECONDS) + era.absolute_slot_to_epoch(era.first_slot + era.epoch_length_seconds) ); let correct = 92595; - let slot = epoch_slot_to_absolute(4, 6195); + let slot = epoch_slot_to_absolute_byron(4, 6195); assert_eq!(slot, correct); let epoch = era.absolute_slot_to_epoch(97507251).unwrap(); assert_eq!(epoch, 423); + + let epoch = era.absolute_slot_to_epoch(99406785).unwrap(); + assert_eq!(epoch, 427); + + let epoch = era.absolute_slot_to_epoch(99100793).unwrap(); + assert_eq!(epoch, 426); + + let epoch = era.absolute_slot_to_epoch(99100852).unwrap(); + assert_eq!(epoch, 427); + + let relative_slot = era.absolute_slot_to_relative(99100852).unwrap(); + assert_eq!(relative_slot, 52); } #[test] @@ -99,4 +121,30 @@ mod tests { let epoch = era.absolute_slot_to_epoch(518340).unwrap(); assert_eq!(epoch, 4); } + + #[test] + fn absolute_slot_to_epoch_preview() { + let era = Era::SHELLEY_PREVIEW; + let epoch = era.absolute_slot_to_epoch(24317818).unwrap(); + assert_eq!(epoch, 281); + let relative_slot = era.absolute_slot_to_relative(24317818).unwrap(); + assert_eq!(relative_slot, 39418); + + let epoch = era.absolute_slot_to_epoch(24278443).unwrap(); + assert_eq!(epoch, 281); + let relative_slot = era.absolute_slot_to_relative(24278443).unwrap(); + assert_eq!(relative_slot, 43); + + let epoch = era.absolute_slot_to_epoch(24278356).unwrap(); + assert_eq!(epoch, 280); + let relative_slot = era.absolute_slot_to_relative(24278356).unwrap(); + assert_eq!(relative_slot, 86356); + let timestamp = era.compute_timestamp(24278356); + assert_eq!(timestamp, 1690934356); + + let epoch = era.absolute_slot_to_epoch(100).unwrap(); + assert_eq!(epoch, 0); + let relative_slot = era.absolute_slot_to_relative(100).unwrap(); + assert_eq!(relative_slot, 100); + } }