@@ -18,6 +18,7 @@ use manifest::{Abi, DataSource, Manifest, Mapping};
18
18
use network_subgraph:: * ;
19
19
use secp256k1:: SecretKey ;
20
20
use std:: sync:: Arc ;
21
+ use std:: time:: SystemTime ;
21
22
use std:: time:: { Duration , Instant } ;
22
23
use std:: { fmt:: Display , str:: FromStr } ;
23
24
use structopt:: StructOpt ;
@@ -148,6 +149,8 @@ struct Config {
148
149
pub oracle_index : Option < u64 > ,
149
150
}
150
151
152
+ const VALID_DEPLOYMENT_CACHE_TTL : Duration = Duration :: from_secs ( 60 * 60 * 24 ) ;
153
+
151
154
#[ tokio:: main]
152
155
async fn main ( ) -> Result < ( ) > {
153
156
common:: main ( run) . await
@@ -159,6 +162,10 @@ async fn run(logger: Logger, config: Config) -> Result<()> {
159
162
let epoch_subgraph =
160
163
EpochBlockOracleSubgraphImpl :: new ( logger. clone ( ) , config. epoch_block_oracle_subgraph ) ;
161
164
let contract: Box < dyn StateManager > = if config. dry_run {
165
+ info ! (
166
+ logger,
167
+ "Running in dry mode: no transactions will be submitted on chain!"
168
+ ) ;
162
169
Box :: new ( StateManagerDryRun :: new ( logger. clone ( ) ) )
163
170
} else {
164
171
let signing_key: & SecretKey = & config. signing_key . unwrap ( ) . parse ( ) ?;
@@ -181,6 +188,10 @@ async fn run(logger: Logger, config: Config) -> Result<()> {
181
188
if config. period > Duration :: from_secs ( 0 ) {
182
189
let mut interval = tokio:: time:: interval ( config. period ) ;
183
190
interval. set_missed_tick_behavior ( MissedTickBehavior :: Skip ) ;
191
+
192
+ // Valid deployments get checked only every VALID_DEPLOYMENT_CACHE_TTL seconds
193
+ let mut valid_deployment_cache: Vec < ( Cid , SystemTime ) > = Vec :: new ( ) ;
194
+
184
195
loop {
185
196
interval. tick ( ) . await ;
186
197
@@ -197,11 +208,16 @@ async fn run(logger: Logger, config: Config) -> Result<()> {
197
208
grace_period,
198
209
epoch_subgraph. clone ( ) ,
199
210
& config. supported_data_source_kinds ,
211
+ valid_deployment_cache. clone ( ) ,
200
212
)
201
213
. await
202
214
{
203
- Ok ( ( ) ) => {
215
+ Ok ( updated_deployment_cache ) => {
204
216
METRICS . reconcile_runs_ok . inc ( ) ;
217
+ valid_deployment_cache = updated_deployment_cache;
218
+ info ! ( logger, "Deployment cache updated" ;
219
+ "count" => valid_deployment_cache. len( )
220
+ ) ;
205
221
}
206
222
Err ( e) => {
207
223
METRICS . reconcile_runs_err . inc ( ) ;
@@ -221,7 +237,7 @@ async fn run(logger: Logger, config: Config) -> Result<()> {
221
237
ipfs. invalidate_cache ( ) ;
222
238
}
223
239
}
224
- reconcile_deny_list (
240
+ match reconcile_deny_list (
225
241
& logger,
226
242
& ipfs,
227
243
& * contract,
@@ -230,8 +246,13 @@ async fn run(logger: Logger, config: Config) -> Result<()> {
230
246
grace_period,
231
247
epoch_subgraph. clone ( ) ,
232
248
& config. supported_data_source_kinds ,
249
+ Vec :: new ( ) ,
233
250
)
234
251
. await
252
+ {
253
+ Ok ( _) => return Ok ( ( ) ) ,
254
+ Err ( e) => return Err ( e) ,
255
+ }
235
256
}
236
257
237
258
// This function is used to create a state manager based on the configuration.
@@ -281,7 +302,8 @@ pub async fn reconcile_deny_list(
281
302
grace_period : Duration ,
282
303
epoch_subgraph : Arc < impl EpochBlockOracleSubgraph > ,
283
304
supported_ds_kinds : & [ String ] ,
284
- ) -> Result < ( ) , Error > {
305
+ valid_deployment_cache : Vec < ( Cid , SystemTime ) > ,
306
+ ) -> Result < Vec < ( Cid , SystemTime ) > , Error > {
285
307
let logger = logger. clone ( ) ;
286
308
287
309
// Fetch supported networks
@@ -300,20 +322,35 @@ pub async fn reconcile_deny_list(
300
322
) ;
301
323
302
324
// Check the availability status of all subgraphs, and gather which should flip the deny flag.
303
- let status_changes : Vec < ( [ u8 ; 32 ] , bool ) > = subgraph
325
+ let deployment_status : Vec < ( [ u8 ; 32 ] , bool , bool , SystemTime ) > = subgraph
304
326
. deployments_over_threshold ( min_signal, grace_period)
305
327
. map ( |deployment| async {
306
328
let deployment = deployment?;
307
329
let id = bytes32_to_cid_v0 ( deployment. id ) ;
308
- let validity = match check ( ipfs, id, & supported_networks, supported_ds_kinds) . await {
309
- Ok ( ( ) ) => Valid :: Yes ,
310
- Err ( CheckError :: Invalid ( e) ) => Valid :: No ( e) ,
311
- Err ( CheckError :: Other ( e) ) => return Err ( e) ,
330
+
331
+ // Valid subgraphs are only checked every VALID_DEPLOYMENT_CACHE_TTL seconds to reduce IPFS requests
332
+ let cached = valid_deployment_cache
333
+ . iter ( )
334
+ . filter ( |( _, last_validated) | {
335
+ last_validated. elapsed ( ) . unwrap ( ) < VALID_DEPLOYMENT_CACHE_TTL
336
+ } )
337
+ . find ( |( cid, _) | * cid == id) ;
338
+
339
+ if cached. is_some ( ) {
340
+ METRICS . valid_deployment_cache_hits . inc ( ) ;
341
+ return Ok ( ( deployment, Valid :: Yes , cached. unwrap ( ) . 1 ) ) ;
342
+ } else {
343
+ let validity = match check ( ipfs, id, & supported_networks, supported_ds_kinds) . await
344
+ {
345
+ Ok ( ( ) ) => Valid :: Yes ,
346
+ Err ( CheckError :: Invalid ( e) ) => Valid :: No ( e) ,
347
+ Err ( CheckError :: Other ( e) ) => return Err ( e) ,
348
+ } ;
349
+ return Ok ( ( deployment, validity, SystemTime :: now ( ) ) ) ;
312
350
} ;
313
- Result :: < _ , Error > :: Ok ( ( deployment, validity) )
314
351
} )
315
352
. buffered ( 100 )
316
- . try_filter_map ( move |( deployment, validity) | {
353
+ . try_filter_map ( move |( deployment, validity, last_validated ) | {
317
354
let logger = logger. clone ( ) ;
318
355
async move {
319
356
info ! ( logger, "Check subgraph" ;
@@ -336,7 +373,7 @@ pub async fn reconcile_deny_list(
336
373
) ;
337
374
}
338
375
} ;
339
- None
376
+ Some ( ( deployment . id , should_deny , false , last_validated ) )
340
377
}
341
378
342
379
// The validity status changed, flip the deny flag.
@@ -347,15 +384,32 @@ pub async fn reconcile_deny_list(
347
384
"status" => should_deny,
348
385
"reason" => validity. to_string( ) ,
349
386
) ;
350
- Some ( ( deployment. id , should_deny) )
387
+ Some ( ( deployment. id , should_deny, true , last_validated ) )
351
388
}
352
389
} )
353
390
}
354
391
} )
355
392
. try_collect ( )
356
393
. await ?;
357
394
358
- state_manager. deny_many ( status_changes) . await
395
+ // Flip on chain status for those deployments that changed
396
+ let changed_deployments = deployment_status
397
+ . iter ( )
398
+ . filter ( |( _, _, status_changed, _) | * status_changed)
399
+ . map ( |( cid, should_deny, _, _) | ( * cid, * should_deny) )
400
+ . collect ( ) ;
401
+ match state_manager. deny_many ( changed_deployments) . await {
402
+ Ok ( _) => { }
403
+ Err ( e) => return Err ( e) ,
404
+ } ;
405
+
406
+ // Return updated deployment cache
407
+ let updated_deployment_cache: Vec < ( Cid , SystemTime ) > = deployment_status
408
+ . iter ( )
409
+ . filter ( |( _, should_deny, _, _) | !* should_deny)
410
+ . map ( |( cid, _, _, last_validated) | ( bytes32_to_cid_v0 ( * cid) , * last_validated) )
411
+ . collect ( ) ;
412
+ Ok ( updated_deployment_cache)
359
413
}
360
414
361
415
enum Valid {
@@ -537,6 +591,7 @@ struct Metrics {
537
591
reconcile_runs_total : prometheus:: IntCounter ,
538
592
reconcile_runs_ok : prometheus:: IntCounter ,
539
593
reconcile_runs_err : prometheus:: IntCounter ,
594
+ valid_deployment_cache_hits : prometheus:: IntCounter ,
540
595
}
541
596
542
597
lazy_static ! {
@@ -561,6 +616,11 @@ impl Metrics {
561
616
"Total reconcile runs with errors"
562
617
)
563
618
. unwrap ( ) ,
619
+ valid_deployment_cache_hits : prometheus:: register_int_counter!(
620
+ "valid_deployment_cache_hits" ,
621
+ "Total valid deployment cache hits"
622
+ )
623
+ . unwrap ( ) ,
564
624
}
565
625
}
566
626
}
0 commit comments