@@ -173,9 +173,12 @@ impl Network {
173173 pub fn time_to_slot ( & self , time : DateTime < Utc > ) -> Option < u64 > {
174174 let genesis = self . genesis_values ( ) ;
175175
176- let byron_start_time = DateTime :: < Utc > :: from_timestamp ( genesis. byron_known_time as i64 , 0 ) ?;
177- let shelley_start_time =
178- DateTime :: < Utc > :: from_timestamp ( genesis. shelley_known_time as i64 , 0 ) ?;
176+ let byron_start_time = i64:: try_from ( genesis. byron_known_time )
177+ . map ( |time| DateTime :: < Utc > :: from_timestamp ( time, 0 ) )
178+ . ok ( ) ??;
179+ let shelley_start_time = i64:: try_from ( genesis. shelley_known_time )
180+ . map ( |time| DateTime :: < Utc > :: from_timestamp ( time, 0 ) )
181+ . ok ( ) ??;
179182
180183 // determine if the given time is in Byron or Shelley era.
181184 if time < byron_start_time {
@@ -186,12 +189,18 @@ impl Network {
186189 // Byron era
187190 let time_diff = time - byron_start_time;
188191 let elapsed_slots = time_diff. num_seconds ( ) / i64:: from ( genesis. byron_slot_length ) ;
189- Some ( genesis. byron_known_slot + elapsed_slots as u64 )
192+
193+ u64:: try_from ( elapsed_slots)
194+ . map ( |elapsed_slots| Some ( genesis. byron_known_slot + elapsed_slots) )
195+ . ok ( ) ?
190196 } else {
191197 // Shelley era
192198 let time_diff = time - shelley_start_time;
193199 let elapsed_slots = time_diff. num_seconds ( ) / i64:: from ( genesis. shelley_slot_length ) ;
194- Some ( genesis. shelley_known_slot + elapsed_slots as u64 )
200+
201+ u64:: try_from ( elapsed_slots)
202+ . map ( |elapsed_slots| Some ( genesis. shelley_known_slot + elapsed_slots) )
203+ . ok ( ) ?
195204 }
196205 }
197206}
@@ -211,6 +220,7 @@ mod tests {
211220 use std:: str:: FromStr ;
212221
213222 use anyhow:: Ok ;
223+ use chrono:: { TimeZone , Utc } ;
214224
215225 use super :: * ;
216226
@@ -234,4 +244,77 @@ mod tests {
234244
235245 Ok ( ( ) )
236246 }
247+
248+ #[ test]
249+ fn test_time_to_slot_before_blockchain ( ) {
250+ let network = Network :: Mainnet ;
251+ let genesis = network. genesis_values ( ) ;
252+
253+ let before_blockchain = Utc
254+ . timestamp_opt ( i64:: try_from ( genesis. byron_known_time ) . unwrap ( ) - 1 , 0 )
255+ . unwrap ( ) ;
256+
257+ // Expect None for time before the blockchain started
258+ assert_eq ! ( network. time_to_slot( before_blockchain) , None ) ;
259+ }
260+
261+ #[ test]
262+ fn test_time_to_slot_byron_era ( ) {
263+ let network = Network :: Mainnet ;
264+ let genesis = network. genesis_values ( ) ;
265+
266+ let byron_start_time = Utc
267+ . timestamp_opt ( i64:: try_from ( genesis. byron_known_time ) . unwrap ( ) , 0 )
268+ . unwrap ( ) ;
269+ let byron_slot_length = i64:: from ( genesis. byron_slot_length ) ;
270+
271+ // A time in the middle of the Byron era
272+ let time = byron_start_time + chrono:: Duration :: seconds ( byron_slot_length * 100 ) ;
273+ let expected_slot = genesis. byron_known_slot + 100 ;
274+
275+ // Expect the correct slot for the given time
276+ assert_eq ! ( network. time_to_slot( time) , Some ( expected_slot) ) ;
277+ }
278+
279+ #[ test]
280+ fn test_time_to_slot_transition_to_shelley ( ) {
281+ let network = Network :: Mainnet ;
282+ let genesis = network. genesis_values ( ) ;
283+
284+ let shelley_start_time = Utc
285+ . timestamp_opt ( i64:: try_from ( genesis. shelley_known_time ) . unwrap ( ) , 0 )
286+ . unwrap ( ) ;
287+ let byron_slot_length = i64:: from ( genesis. byron_slot_length ) ;
288+
289+ // A time just before Shelley era starts
290+ let time = shelley_start_time - chrono:: Duration :: seconds ( 1 ) ;
291+ let elapsed_slots = ( time
292+ - Utc
293+ . timestamp_opt ( i64:: try_from ( genesis. byron_known_time ) . unwrap ( ) , 0 )
294+ . unwrap ( ) )
295+ . num_seconds ( )
296+ / byron_slot_length;
297+ let expected_slot = genesis. byron_known_slot + u64:: try_from ( elapsed_slots) . unwrap ( ) ;
298+
299+ // Expect the slot to be in the Byron era
300+ assert_eq ! ( network. time_to_slot( time) , Some ( expected_slot) ) ;
301+ }
302+
303+ #[ test]
304+ fn test_time_to_slot_shelley_era ( ) {
305+ let network = Network :: Mainnet ;
306+ let genesis = network. genesis_values ( ) ;
307+
308+ let shelley_start_time = Utc
309+ . timestamp_opt ( i64:: try_from ( genesis. shelley_known_time ) . unwrap ( ) , 0 )
310+ . unwrap ( ) ;
311+ let shelley_slot_length = i64:: from ( genesis. shelley_slot_length ) ;
312+
313+ // A time in the middle of the Shelley era
314+ let time = shelley_start_time + chrono:: Duration :: seconds ( shelley_slot_length * 200 ) ;
315+ let expected_slot = genesis. shelley_known_slot + 200 ;
316+
317+ // Expect the correct slot for the given time
318+ assert_eq ! ( network. time_to_slot( time) , Some ( expected_slot) ) ;
319+ }
237320}
0 commit comments