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,63 @@ 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_hex_str ( & str) ,
595+ None => return Ok ( BlockTime :: NONE ) ,
596+ } ;
597+ }
598+ }
599+
565600impl BlockTime {
566601 /// A timestamp from a long long time ago used to indicate that we don't
567602 /// have a timestamp
568- pub const NONE : Self = Self ( Timestamp :: NONE ) ;
603+ pub const NONE : Self = Self :: MIN ;
569604
570605 pub const MAX : Self = Self ( Timestamp :: MAX ) ;
571606
572- pub const MIN : Self = Self ( Timestamp :: MIN ) ;
607+ pub const MIN : Self = Self ( Timestamp ( DateTime :: from_timestamp_nanos ( 0 ) ) ) ;
608+
609+ pub fn from_hex_str ( ts : & str ) -> Result < Self , ParseIntError > {
610+ let ( radix, idx) = if ts. starts_with ( "0x" ) {
611+ ( 16 , 2 )
612+ } else {
613+ ( 10 , 0 )
614+ } ;
615+
616+ u64:: from_str_radix ( & ts[ idx..] , radix) . map ( |ts| BlockTime :: since_epoch ( ts as i64 , 0 ) )
617+ }
573618
574619 /// Construct a block time that is the given number of seconds and
575620 /// nanoseconds after the Unix epoch
@@ -586,7 +631,12 @@ impl BlockTime {
586631 /// hourly rollups in tests
587632 #[ cfg( debug_assertions) ]
588633 pub fn for_test ( ptr : & BlockPtr ) -> Self {
589- Self :: since_epoch ( ptr. number as i64 * 45 * 60 , 0 )
634+ Self :: for_test_number ( & ptr. number )
635+ }
636+
637+ #[ cfg( debug_assertions) ]
638+ pub fn for_test_number ( number : & BlockNumber ) -> Self {
639+ Self :: since_epoch ( * number as i64 * 45 * 60 , 0 )
590640 }
591641
592642 pub fn as_secs_since_epoch ( & self ) -> i64 {
0 commit comments