diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index db9363643a3..588bdd8aca2 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1313,7 +1313,7 @@ where let now = Instant::now(); // Calculate the available capacity for queries triggered by background jobs. - let mut jobs_query_capacity = JOBS_MAX_QUERIES - self.queries.size(); + let mut jobs_query_capacity = JOBS_MAX_QUERIES.saturating_sub(self.queries.size()); // Run the periodic provider announcement job. if let Some(mut job) = self.add_provider_job.take() { diff --git a/protocols/kad/src/behaviour/test.rs b/protocols/kad/src/behaviour/test.rs index 5bf8db1ba0b..7786762dda2 100644 --- a/protocols/kad/src/behaviour/test.rs +++ b/protocols/kad/src/behaviour/test.rs @@ -623,3 +623,34 @@ fn add_provider() { QuickCheck::new().tests(3).quickcheck(prop as fn(_,_)) } +/// User code should be able to start queries beyond the internal +/// query limit for background jobs. Originally this even produced an +/// arithmetic overflow, see https://github.com/libp2p/rust-libp2p/issues/1290. +#[test] +fn exceed_jobs_max_queries() { + let (_, mut swarms) = build_nodes(1); + let num = JOBS_MAX_QUERIES + 1; + for _ in 0 .. num { + swarms[0].bootstrap(); + } + + assert_eq!(swarms[0].queries.size(), num); + + current_thread::run( + future::poll_fn(move || { + for _ in 0 .. num { + // There are no other nodes, so the queries finish instantly. + if let Ok(Async::Ready(Some(e))) = swarms[0].poll() { + if let KademliaEvent::BootstrapResult(r) = e { + assert!(r.is_ok(), "Unexpected error") + } else { + panic!("Unexpected event: {:?}", e) + } + } else { + panic!("Expected event") + } + } + Ok(Async::Ready(())) + })) +} +