diff --git a/graph/src/components/store/traits.rs b/graph/src/components/store/traits.rs index a3fa34e0d87..158e75aa87d 100644 --- a/graph/src/components/store/traits.rs +++ b/graph/src/components/store/traits.rs @@ -389,7 +389,7 @@ pub trait ChainStore: Send + Sync + 'static { async fn block_number( &self, hash: &BlockHash, - ) -> Result)>, StoreError>; + ) -> Result)>, StoreError>; /// Tries to retrieve all transactions receipts for a given block. async fn transaction_receipts_in_block( @@ -443,7 +443,7 @@ pub trait QueryStore: Send + Sync { async fn block_number_with_timestamp( &self, block_hash: &BlockHash, - ) -> Result)>, StoreError>; + ) -> Result)>, StoreError>; fn wait_stats(&self) -> Result; diff --git a/graphql/src/schema/meta.graphql b/graphql/src/schema/meta.graphql index 1a1faf68878..84c2540e9ec 100644 --- a/graphql/src/schema/meta.graphql +++ b/graphql/src/schema/meta.graphql @@ -55,8 +55,8 @@ type _Block_ { hash: Bytes "The block number" number: Int! - "Timestamp of the block if available, format depends on the chain" - timestamp: String + "Integer representation of the timestamp store in blocks for the chain" + timestamp: Int } enum _SubgraphErrorPolicy_ { diff --git a/graphql/src/store/resolver.rs b/graphql/src/store/resolver.rs index 89a635c826e..0dfbe93377d 100644 --- a/graphql/src/store/resolver.rs +++ b/graphql/src/store/resolver.rs @@ -36,7 +36,7 @@ pub struct StoreResolver { #[derive(Clone, Debug)] pub(crate) struct BlockPtrTs { pub ptr: BlockPtr, - pub timestamp: Option, + pub timestamp: Option, } impl From for BlockPtrTs { @@ -142,7 +142,7 @@ impl StoreResolver { async fn get_block_ts( store: &dyn QueryStore, ptr: &BlockPtr, - ) -> Result, QueryExecutionError> { + ) -> Result, QueryExecutionError> { match store .block_number_with_timestamp(&ptr.hash) .await @@ -247,7 +247,7 @@ impl StoreResolver { let timestamp = self.block_ptr.as_ref().map(|ptr| { ptr.timestamp .clone() - .map(|ts| r::Value::String(ts)) + .map(|ts| r::Value::Int(ts as i64)) .unwrap_or(r::Value::Null) }); diff --git a/store/postgres/src/chain_store.rs b/store/postgres/src/chain_store.rs index 0b2fea9a295..74a9101bed8 100644 --- a/store/postgres/src/chain_store.rs +++ b/store/postgres/src/chain_store.rs @@ -595,7 +595,7 @@ mod data { &self, conn: &PgConnection, hash: &BlockHash, - ) -> Result)>, StoreError> { + ) -> Result)>, StoreError> { const TIMESTAMP_QUERY: &str = "coalesce(data->'block'->>'timestamp', data->>'timestamp')"; @@ -622,7 +622,7 @@ mod data { Some((number, ts)) => { let number = BlockNumber::try_from(number) .map_err(|e| StoreError::QueryExecutionError(e.to_string()))?; - Ok(Some((number, ts))) + Ok(Some((number, crate::chain_store::try_parse_timestamp(ts)?))) } } } @@ -1701,7 +1701,7 @@ impl ChainStoreTrait for ChainStore { async fn block_number( &self, hash: &BlockHash, - ) -> Result)>, StoreError> { + ) -> Result)>, StoreError> { let hash = hash.clone(); let storage = self.storage.clone(); let chain = self.chain.clone(); @@ -1731,6 +1731,28 @@ impl ChainStoreTrait for ChainStore { } } +fn try_parse_timestamp(ts: Option) -> Result, StoreError> { + let ts = match ts { + Some(str) => str, + None => return Ok(None), + }; + + let (radix, idx) = if ts.starts_with("0x") { + (16, 2) + } else { + (10, 0) + }; + + u64::from_str_radix(&ts[idx..], radix) + .map_err(|err| { + StoreError::QueryExecutionError(format!( + "unexpected timestamp format {}, err: {}", + ts, err + )) + }) + .map(Some) +} + impl EthereumCallCache for ChainStore { fn get_call( &self, diff --git a/store/postgres/src/query_store.rs b/store/postgres/src/query_store.rs index 7218394b118..ccc5142d77d 100644 --- a/store/postgres/src/query_store.rs +++ b/store/postgres/src/query_store.rs @@ -63,7 +63,7 @@ impl QueryStoreTrait for QueryStore { async fn block_number_with_timestamp( &self, block_hash: &BlockHash, - ) -> Result)>, StoreError> { + ) -> Result)>, StoreError> { // We should also really check that the block with the given hash is // on the chain starting at the subgraph's current head. That check is // very expensive though with the data structures we have currently diff --git a/store/postgres/tests/store.rs b/store/postgres/tests/store.rs index 19e3f1ec9b2..156c826ac90 100644 --- a/store/postgres/tests/store.rs +++ b/store/postgres/tests/store.rs @@ -1996,7 +1996,7 @@ fn cleanup_cached_blocks() { /// checks if retrieving the timestamp from the data blob works. /// on ethereum, the block has timestamp as U256 so it will always have a value fn parse_timestamp() { - const EXPECTED_TS: &str = "0x62ceae26"; + const EXPECTED_TS: u64 = 1657712166; run_test(|store, _, _| async move { use block_store::*;