@@ -26,13 +26,34 @@ pub struct StoreResolver {
26
26
logger : Logger ,
27
27
pub ( crate ) store : Arc < dyn QueryStore > ,
28
28
subscription_manager : Arc < dyn SubscriptionManager > ,
29
- pub ( crate ) block_ptr : Option < BlockPtr > ,
29
+ pub ( crate ) block_ptr : Option < BlockPtrTs > ,
30
30
deployment : DeploymentHash ,
31
31
has_non_fatal_errors : bool ,
32
32
error_policy : ErrorPolicy ,
33
33
graphql_metrics : Arc < GraphQLMetrics > ,
34
34
}
35
35
36
+ #[ derive( Clone , Debug ) ]
37
+ pub ( crate ) struct BlockPtrTs {
38
+ pub ptr : BlockPtr ,
39
+ pub timestamp : Option < String > ,
40
+ }
41
+
42
+ impl From < BlockPtr > for BlockPtrTs {
43
+ fn from ( ptr : BlockPtr ) -> Self {
44
+ Self {
45
+ ptr,
46
+ timestamp : None ,
47
+ }
48
+ }
49
+ }
50
+
51
+ impl From < & BlockPtrTs > for BlockPtr {
52
+ fn from ( ptr : & BlockPtrTs ) -> Self {
53
+ ptr. ptr . cheap_clone ( )
54
+ }
55
+ }
56
+
36
57
impl CheapClone for StoreResolver { }
37
58
38
59
impl StoreResolver {
@@ -80,7 +101,7 @@ impl StoreResolver {
80
101
let block_ptr = Self :: locate_block ( store_clone. as_ref ( ) , bc, state) . await ?;
81
102
82
103
let has_non_fatal_errors = store
83
- . has_deterministic_errors ( block_ptr. block_number ( ) )
104
+ . has_deterministic_errors ( block_ptr. ptr . block_number ( ) )
84
105
. await ?;
85
106
86
107
let resolver = StoreResolver {
@@ -99,15 +120,16 @@ impl StoreResolver {
99
120
pub fn block_number ( & self ) -> BlockNumber {
100
121
self . block_ptr
101
122
. as_ref ( )
102
- . map ( |ptr| ptr. number as BlockNumber )
123
+ . map ( |ptr| ptr. ptr . number as BlockNumber )
103
124
. unwrap_or ( BLOCK_NUMBER_MAX )
104
125
}
105
126
127
+ /// locate_block returns the block pointer and it's timestamp when available.
106
128
async fn locate_block (
107
129
store : & dyn QueryStore ,
108
130
bc : BlockConstraint ,
109
131
state : & DeploymentState ,
110
- ) -> Result < BlockPtr , QueryExecutionError > {
132
+ ) -> Result < BlockPtrTs , QueryExecutionError > {
111
133
fn block_queryable (
112
134
state : & DeploymentState ,
113
135
block : BlockNumber ,
@@ -117,23 +139,39 @@ impl StoreResolver {
117
139
. map_err ( |msg| QueryExecutionError :: ValueParseError ( "block.number" . to_owned ( ) , msg) )
118
140
}
119
141
142
+ fn get_block_ts (
143
+ store : & dyn QueryStore ,
144
+ ptr : & BlockPtr ,
145
+ ) -> Result < Option < String > , QueryExecutionError > {
146
+ match store
147
+ . block_number_with_timestamp ( & ptr. hash )
148
+ . map_err ( Into :: < QueryExecutionError > :: into) ?
149
+ {
150
+ Some ( ( _, Some ( ts) ) ) => Ok ( Some ( ts) ) ,
151
+ _ => Ok ( None ) ,
152
+ }
153
+ }
154
+
120
155
match bc {
121
156
BlockConstraint :: Hash ( hash) => {
122
157
let ptr = store
123
- . block_number ( & hash)
158
+ . block_number_with_timestamp ( & hash)
124
159
. map_err ( Into :: into)
125
- . and_then ( |number | {
126
- number
160
+ . and_then ( |result | {
161
+ result
127
162
. ok_or_else ( || {
128
163
QueryExecutionError :: ValueParseError (
129
164
"block.hash" . to_owned ( ) ,
130
165
"no block with that hash found" . to_owned ( ) ,
131
166
)
132
167
} )
133
- . map ( |number| BlockPtr :: new ( hash, number) )
168
+ . map ( |( number, ts) | BlockPtrTs {
169
+ ptr : BlockPtr :: new ( hash, number) ,
170
+ timestamp : ts,
171
+ } )
134
172
} ) ?;
135
173
136
- block_queryable ( state, ptr. number ) ?;
174
+ block_queryable ( state, ptr. ptr . number ) ?;
137
175
Ok ( ptr)
138
176
}
139
177
BlockConstraint :: Number ( number) => {
@@ -144,7 +182,7 @@ impl StoreResolver {
144
182
// always return an all zeroes hash when users specify
145
183
// a block number
146
184
// See 7a7b9708-adb7-4fc2-acec-88680cb07ec1
147
- Ok ( BlockPtr :: from ( ( web3:: types:: H256 :: zero ( ) , number as u64 ) ) )
185
+ Ok ( BlockPtr :: from ( ( web3:: types:: H256 :: zero ( ) , number as u64 ) ) . into ( ) )
148
186
}
149
187
BlockConstraint :: Min ( min) => {
150
188
let ptr = state. latest_block . cheap_clone ( ) ;
@@ -158,9 +196,18 @@ impl StoreResolver {
158
196
) ,
159
197
) ) ;
160
198
}
161
- Ok ( ptr)
199
+ let timestamp = get_block_ts ( store, & state. latest_block ) ?;
200
+
201
+ Ok ( BlockPtrTs { ptr, timestamp } )
202
+ }
203
+ BlockConstraint :: Latest => {
204
+ let timestamp = get_block_ts ( store, & state. latest_block ) ?;
205
+
206
+ Ok ( BlockPtrTs {
207
+ ptr : state. latest_block . cheap_clone ( ) ,
208
+ timestamp,
209
+ } )
162
210
}
163
- BlockConstraint :: Latest => Ok ( state. latest_block . cheap_clone ( ) ) ,
164
211
}
165
212
}
166
213
@@ -181,7 +228,7 @@ impl StoreResolver {
181
228
// locate_block indicates that we do not have a block hash
182
229
// by setting the hash to `zero`
183
230
// See 7a7b9708-adb7-4fc2-acec-88680cb07ec1
184
- let hash_h256 = ptr. hash_as_h256 ( ) ;
231
+ let hash_h256 = ptr. ptr . hash_as_h256 ( ) ;
185
232
if hash_h256 == web3:: types:: H256 :: zero ( ) {
186
233
None
187
234
} else {
@@ -192,12 +239,21 @@ impl StoreResolver {
192
239
let number = self
193
240
. block_ptr
194
241
. as_ref ( )
195
- . map ( |ptr| r:: Value :: Int ( ( ptr. number as i32 ) . into ( ) ) )
242
+ . map ( |ptr| r:: Value :: Int ( ( ptr. ptr . number as i32 ) . into ( ) ) )
196
243
. unwrap_or ( r:: Value :: Null ) ;
244
+
245
+ let timestamp = self . block_ptr . as_ref ( ) . map ( |ptr| {
246
+ ptr. timestamp
247
+ . clone ( )
248
+ . map ( |ts| r:: Value :: String ( ts) )
249
+ . unwrap_or ( r:: Value :: Null )
250
+ } ) ;
251
+
197
252
let mut map = BTreeMap :: new ( ) ;
198
253
let block = object ! {
199
254
hash: hash,
200
255
number: number,
256
+ timestamp: timestamp,
201
257
__typename: BLOCK_FIELD_TYPE
202
258
} ;
203
259
map. insert ( "prefetch:block" . into ( ) , r:: Value :: List ( vec ! [ block] ) ) ;
0 commit comments