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