@@ -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
result_size : Arc < ResultSizeMetrics > ,
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_non_fatal_errors ( Some ( block_ptr. block_number ( ) ) )
103
+ . has_non_fatal_errors ( Some ( 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 check_ptr (
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
- check_ptr ( state, ptr. number ) ?;
173
+ check_ptr ( state, ptr. ptr . number ) ?;
136
174
Ok ( ptr)
137
175
}
138
176
BlockConstraint :: Number ( number) => {
@@ -143,13 +181,26 @@ 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 ( number) => {
149
187
check_ptr ( state, number) ?;
150
- Ok ( state. latest_block . cheap_clone ( ) )
188
+
189
+ let timestamp = get_block_ts ( store, & state. latest_block ) ?;
190
+
191
+ Ok ( BlockPtrTs {
192
+ ptr : state. latest_block . cheap_clone ( ) ,
193
+ timestamp,
194
+ } )
195
+ }
196
+ BlockConstraint :: Latest => {
197
+ let timestamp = get_block_ts ( store, & state. latest_block ) ?;
198
+
199
+ Ok ( BlockPtrTs {
200
+ ptr : state. latest_block . cheap_clone ( ) ,
201
+ timestamp,
202
+ } )
151
203
}
152
- BlockConstraint :: Latest => Ok ( state. latest_block . cheap_clone ( ) ) ,
153
204
}
154
205
}
155
206
@@ -170,7 +221,7 @@ impl StoreResolver {
170
221
// locate_block indicates that we do not have a block hash
171
222
// by setting the hash to `zero`
172
223
// See 7a7b9708-adb7-4fc2-acec-88680cb07ec1
173
- let hash_h256 = ptr. hash_as_h256 ( ) ;
224
+ let hash_h256 = ptr. ptr . hash_as_h256 ( ) ;
174
225
if hash_h256 == web3:: types:: H256 :: zero ( ) {
175
226
None
176
227
} else {
@@ -181,12 +232,21 @@ impl StoreResolver {
181
232
let number = self
182
233
. block_ptr
183
234
. as_ref ( )
184
- . map ( |ptr| r:: Value :: Int ( ( ptr. number as i32 ) . into ( ) ) )
235
+ . map ( |ptr| r:: Value :: Int ( ( ptr. ptr . number as i32 ) . into ( ) ) )
185
236
. unwrap_or ( r:: Value :: Null ) ;
237
+
238
+ let timestamp = self . block_ptr . as_ref ( ) . map ( |ptr| {
239
+ ptr. timestamp
240
+ . clone ( )
241
+ . map ( |ts| r:: Value :: String ( ts) )
242
+ . unwrap_or ( r:: Value :: Null )
243
+ } ) ;
244
+
186
245
let mut map = BTreeMap :: new ( ) ;
187
246
let block = object ! {
188
247
hash: hash,
189
248
number: number,
249
+ timestamp: timestamp,
190
250
__typename: BLOCK_FIELD_TYPE
191
251
} ;
192
252
map. insert ( "prefetch:block" . into ( ) , r:: Value :: List ( vec ! [ block] ) ) ;
0 commit comments