1
1
use anyhow:: anyhow;
2
+ use chrono:: DateTime ;
2
3
use diesel:: deserialize:: FromSql ;
3
4
use diesel:: pg:: Pg ;
4
5
use diesel:: serialize:: { Output , ToSql } ;
@@ -7,6 +8,7 @@ use diesel::sql_types::{Bytea, Nullable, Text};
7
8
use diesel_derives:: { AsExpression , FromSqlRow } ;
8
9
use serde:: { Deserialize , Deserializer } ;
9
10
use std:: convert:: TryFrom ;
11
+ use std:: num:: ParseIntError ;
10
12
use std:: time:: Duration ;
11
13
use std:: { fmt, str:: FromStr } ;
12
14
use web3:: types:: { Block , H256 , U256 , U64 } ;
@@ -16,9 +18,9 @@ use crate::components::store::BlockNumber;
16
18
use crate :: data:: graphql:: IntoValue ;
17
19
use crate :: data:: store:: scalar:: Timestamp ;
18
20
use crate :: derive:: CheapClone ;
19
- use crate :: object;
20
21
use crate :: prelude:: { r, Value } ;
21
22
use crate :: util:: stable_hash_glue:: { impl_stable_hash, AsBytes } ;
23
+ use crate :: { bail, object} ;
22
24
23
25
/// A simple marker for byte arrays that are really block hashes
24
26
#[ derive( Clone , Default , PartialEq , Eq , Hash , FromSqlRow , AsExpression ) ]
@@ -477,10 +479,7 @@ impl TryFrom<(Option<H256>, Option<U64>, H256, U256)> for ExtendedBlockPtr {
477
479
let block_number =
478
480
i32:: try_from ( number) . map_err ( |_| anyhow ! ( "Block number out of range" ) ) ?;
479
481
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) ?;
484
483
485
484
Ok ( ExtendedBlockPtr {
486
485
hash : hash. into ( ) ,
@@ -497,16 +496,13 @@ impl TryFrom<(H256, i32, H256, U256)> for ExtendedBlockPtr {
497
496
fn try_from ( tuple : ( H256 , i32 , H256 , U256 ) ) -> Result < Self , Self :: Error > {
498
497
let ( hash, block_number, parent_hash, timestamp_u256) = tuple;
499
498
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) ?;
504
500
505
501
Ok ( ExtendedBlockPtr {
506
502
hash : hash. into ( ) ,
507
503
number : block_number,
508
504
parent_hash : parent_hash. into ( ) ,
509
- timestamp : block_time ,
505
+ timestamp,
510
506
} )
511
507
}
512
508
}
@@ -562,14 +558,63 @@ impl fmt::Display for ChainIdentifier {
562
558
#[ diesel( sql_type = Timestamptz ) ]
563
559
pub struct BlockTime ( Timestamp ) ;
564
560
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
+
565
600
impl BlockTime {
566
601
/// A timestamp from a long long time ago used to indicate that we don't
567
602
/// have a timestamp
568
- pub const NONE : Self = Self ( Timestamp :: NONE ) ;
603
+ pub const NONE : Self = Self :: MIN ;
569
604
570
605
pub const MAX : Self = Self ( Timestamp :: MAX ) ;
571
606
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
+ }
573
618
574
619
/// Construct a block time that is the given number of seconds and
575
620
/// nanoseconds after the Unix epoch
@@ -586,7 +631,12 @@ impl BlockTime {
586
631
/// hourly rollups in tests
587
632
#[ cfg( debug_assertions) ]
588
633
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 )
590
640
}
591
641
592
642
pub fn as_secs_since_epoch ( & self ) -> i64 {
0 commit comments