Skip to content
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 102 additions & 3 deletions rust/cardano-chain-follower/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,38 @@ impl Network {
///
/// The Slot does not have to be a valid slot present in the blockchain.
#[must_use]
pub fn time_to_slot(&self, _time: DateTime<Utc>) -> Option<u64> {
// TODO: Implement this, for now just return None.
None
pub fn time_to_slot(&self, time: DateTime<Utc>) -> Option<u64> {
let genesis = self.genesis_values();

let byron_start_time = i64::try_from(genesis.byron_known_time)
.map(|time| DateTime::<Utc>::from_timestamp(time, 0))
.ok()??;
let shelley_start_time = i64::try_from(genesis.shelley_known_time)
.map(|time| DateTime::<Utc>::from_timestamp(time, 0))
.ok()??;

// determine if the given time is in Byron or Shelley era.
if time < byron_start_time {
return None;
}

if time < shelley_start_time {
// Byron era
let time_diff = time - byron_start_time;
let elapsed_slots = time_diff.num_seconds() / i64::from(genesis.byron_slot_length);

u64::try_from(elapsed_slots)
.map(|elapsed_slots| Some(genesis.byron_known_slot + elapsed_slots))
.ok()?
} else {
// Shelley era
let time_diff = time - shelley_start_time;
let elapsed_slots = time_diff.num_seconds() / i64::from(genesis.shelley_slot_length);

u64::try_from(elapsed_slots)
.map(|elapsed_slots| Some(genesis.shelley_known_slot + elapsed_slots))
.ok()?
}
}
}

Expand All @@ -191,6 +220,7 @@ mod tests {
use std::str::FromStr;

use anyhow::Ok;
use chrono::{TimeZone, Utc};

use super::*;

Expand All @@ -214,4 +244,73 @@ mod tests {

Ok(())
}

#[test]
fn test_time_to_slot_before_blockchain() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

let before_blockchain = Utc
.timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap() - 1, 0)
.unwrap();

assert_eq!(network.time_to_slot(before_blockchain), None);
}

#[test]
fn test_time_to_slot_byron_era() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

let byron_start_time = Utc
.timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap(), 0)
.unwrap();
let byron_slot_length = i64::from(genesis.byron_slot_length);

// a time in the middle of the Byron era.
let time = byron_start_time + chrono::Duration::seconds(byron_slot_length * 100);
let expected_slot = genesis.byron_known_slot + 100;

assert_eq!(network.time_to_slot(time), Some(expected_slot));
}

#[test]
fn test_time_to_slot_transition_to_shelley() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

let shelley_start_time = Utc
.timestamp_opt(i64::try_from(genesis.shelley_known_time).unwrap(), 0)
.unwrap();
let byron_slot_length = i64::from(genesis.byron_slot_length);

// a time just before Shelley era starts.
let time = shelley_start_time - chrono::Duration::seconds(1);
let elapsed_slots = (time
- Utc
.timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap(), 0)
.unwrap())
.num_seconds()
/ byron_slot_length;
let expected_slot = genesis.byron_known_slot + u64::try_from(elapsed_slots).unwrap();

assert_eq!(network.time_to_slot(time), Some(expected_slot));
}

#[test]
fn test_time_to_slot_shelley_era() {
let network = Network::Mainnet;
let genesis = network.genesis_values();

let shelley_start_time = Utc
.timestamp_opt(i64::try_from(genesis.shelley_known_time).unwrap(), 0)
.unwrap();
let shelley_slot_length = i64::from(genesis.shelley_slot_length);

// a time in the middle of the Shelley era.
let time = shelley_start_time + chrono::Duration::seconds(shelley_slot_length * 200);
let expected_slot = genesis.shelley_known_slot + 200;

assert_eq!(network.time_to_slot(time), Some(expected_slot));
}
}