11use anyhow:: anyhow;
2+ use chrono:: DateTime ;
23use diesel:: deserialize:: FromSql ;
34use diesel:: pg:: Pg ;
45use diesel:: serialize:: { Output , ToSql } ;
@@ -7,6 +8,7 @@ use diesel::sql_types::{Bytea, Nullable, Text};
78use diesel_derives:: { AsExpression , FromSqlRow } ;
89use serde:: { Deserialize , Deserializer } ;
910use std:: convert:: TryFrom ;
11+ use std:: num:: ParseIntError ;
1012use std:: time:: Duration ;
1113use std:: { fmt, str:: FromStr } ;
1214use web3:: types:: { Block , H256 , U256 , U64 } ;
@@ -16,9 +18,9 @@ use crate::components::store::BlockNumber;
1618use crate :: data:: graphql:: IntoValue ;
1719use crate :: data:: store:: scalar:: Timestamp ;
1820use crate :: derive:: CheapClone ;
19- use crate :: object;
2021use crate :: prelude:: { r, Value } ;
2122use crate :: util:: stable_hash_glue:: { impl_stable_hash, AsBytes } ;
23+ use crate :: { bail, object} ;
2224
2325/// A simple marker for byte arrays that are really block hashes
2426#[ derive( Clone , Default , PartialEq , Eq , Hash , FromSqlRow , AsExpression ) ]
@@ -477,10 +479,7 @@ impl TryFrom<(Option<H256>, Option<U64>, H256, U256)> for ExtendedBlockPtr {
477479 let block_number =
478480 i32:: try_from ( number) . map_err ( |_| anyhow ! ( "Block number out of range" ) ) ?;
479481
480- // Convert `U256` to `BlockTime`
481- let secs =
482- i64:: try_from ( timestamp_u256) . map_err ( |_| anyhow ! ( "Timestamp out of range for i64" ) ) ?;
483- let block_time = BlockTime :: since_epoch ( secs, 0 ) ;
482+ let block_time = BlockTime :: try_from ( timestamp_u256) ?;
484483
485484 Ok ( ExtendedBlockPtr {
486485 hash : hash. into ( ) ,
@@ -497,16 +496,13 @@ impl TryFrom<(H256, i32, H256, U256)> for ExtendedBlockPtr {
497496 fn try_from ( tuple : ( H256 , i32 , H256 , U256 ) ) -> Result < Self , Self :: Error > {
498497 let ( hash, block_number, parent_hash, timestamp_u256) = tuple;
499498
500- // Convert `U256` to `BlockTime`
501- let secs =
502- i64:: try_from ( timestamp_u256) . map_err ( |_| anyhow ! ( "Timestamp out of range for i64" ) ) ?;
503- let block_time = BlockTime :: since_epoch ( secs, 0 ) ;
499+ let timestamp = BlockTime :: try_from ( timestamp_u256) ?;
504500
505501 Ok ( ExtendedBlockPtr {
506502 hash : hash. into ( ) ,
507503 number : block_number,
508504 parent_hash : parent_hash. into ( ) ,
509- timestamp : block_time ,
505+ timestamp,
510506 } )
511507 }
512508}
@@ -562,14 +558,67 @@ impl fmt::Display for ChainIdentifier {
562558#[ diesel( sql_type = Timestamptz ) ]
563559pub struct BlockTime ( Timestamp ) ;
564560
561+ impl Default for BlockTime {
562+ fn default ( ) -> Self {
563+ BlockTime :: NONE
564+ }
565+ }
566+
567+ impl TryFrom < BlockTime > for U256 {
568+ type Error = anyhow:: Error ;
569+
570+ fn try_from ( value : BlockTime ) -> Result < Self , Self :: Error > {
571+ if value. as_secs_since_epoch ( ) < 0 {
572+ bail ! ( "unable to convert block time into U256" ) ;
573+ }
574+
575+ Ok ( U256 :: from ( value. as_secs_since_epoch ( ) as u64 ) )
576+ }
577+ }
578+
579+ impl TryFrom < U256 > for BlockTime {
580+ type Error = anyhow:: Error ;
581+
582+ fn try_from ( value : U256 ) -> Result < Self , Self :: Error > {
583+ i64:: try_from ( value)
584+ . map_err ( |_| anyhow ! ( "Timestamp out of range for i64" ) )
585+ . map ( |ts| BlockTime :: since_epoch ( ts, 0 ) )
586+ }
587+ }
588+
589+ impl TryFrom < Option < String > > for BlockTime {
590+ type Error = ParseIntError ;
591+
592+ fn try_from ( ts : Option < String > ) -> Result < Self , Self :: Error > {
593+ match ts {
594+ Some ( str) => return BlockTime :: from_str ( & str) ,
595+ None => return Ok ( BlockTime :: NONE ) ,
596+ } ;
597+ }
598+ }
599+
600+ impl FromStr for BlockTime {
601+ type Err = ParseIntError ;
602+
603+ fn from_str ( ts : & str ) -> Result < Self , Self :: Err > {
604+ let ( radix, idx) = if ts. starts_with ( "0x" ) {
605+ ( 16 , 2 )
606+ } else {
607+ ( 10 , 0 )
608+ } ;
609+
610+ u64:: from_str_radix ( & ts[ idx..] , radix) . map ( |ts| BlockTime :: since_epoch ( ts as i64 , 0 ) )
611+ }
612+ }
613+
565614impl BlockTime {
566- /// A timestamp from a long long time ago used to indicate that we don't
567- /// have a timestamp
568- pub const NONE : Self = Self ( Timestamp :: NONE ) ;
615+ // // / A timestamp from a long long time ago used to indicate that we don't
616+ // // / have a timestamp
617+ pub const NONE : Self = Self :: MIN ;
569618
570619 pub const MAX : Self = Self ( Timestamp :: MAX ) ;
571620
572- pub const MIN : Self = Self ( Timestamp :: MIN ) ;
621+ pub const MIN : Self = Self ( Timestamp ( DateTime :: from_timestamp_nanos ( 0 ) ) ) ;
573622
574623 /// Construct a block time that is the given number of seconds and
575624 /// nanoseconds after the Unix epoch
@@ -586,7 +635,12 @@ impl BlockTime {
586635 /// hourly rollups in tests
587636 #[ cfg( debug_assertions) ]
588637 pub fn for_test ( ptr : & BlockPtr ) -> Self {
589- Self :: since_epoch ( ptr. number as i64 * 45 * 60 , 0 )
638+ Self :: for_test_number ( & ptr. number )
639+ }
640+
641+ #[ cfg( debug_assertions) ]
642+ pub fn for_test_number ( number : & BlockNumber ) -> Self {
643+ Self :: since_epoch ( * number as i64 * 45 * 60 , 0 )
590644 }
591645
592646 pub fn as_secs_since_epoch ( & self ) -> i64 {
0 commit comments