diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 3d669e417c..51438a23cc 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -21,6 +21,7 @@ #[cfg(test)] mod tests; +use std::time::{Duration, Instant}; use futures::{channel::oneshot, FutureExt as _}; use polkadot_node_subsystem::{ messages::{ @@ -38,6 +39,9 @@ use sp_keystore::{CryptoStore, SyncCryptoStorePtr}; use sp_application_crypto::{Public, AppKey}; const LOG_TARGET: &str = "parachain::gossip-support"; +// How much time should we wait since the last +// authority discovery resolution failure. +const BACKOFF_DURATION: Duration = Duration::from_secs(5); /// The Gossip Support subsystem. pub struct GossipSupport { @@ -47,7 +51,10 @@ pub struct GossipSupport { #[derive(Default)] struct State { last_session_index: Option, - force_request: bool, + // Some(timestamp) if we failed to resolve + // at least a third of authorities the last time. + // `None` otherwise. + last_failure: Option, } impl GossipSupport { @@ -162,13 +169,20 @@ impl State { ) -> Result<(), util::Error> { for leaf in leaves { let current_index = util::request_session_index_for_child(leaf, ctx.sender()).await.await??; + let since_failure = self.last_failure.map(|i| i.elapsed()).unwrap_or_default(); + let force_request = since_failure >= BACKOFF_DURATION; let maybe_new_session = match self.last_session_index { - Some(i) if current_index <= i && !self.force_request => None, + Some(i) if current_index <= i && !force_request => None, _ => Some((current_index, leaf)), }; if let Some((new_session, relay_parent)) = maybe_new_session { - tracing::debug!(target: LOG_TARGET, %new_session, "New session detected"); + tracing::debug!( + target: LOG_TARGET, + %new_session, + %force_request, + "New session detected", + ); let authorities = determine_relevant_authorities(ctx, relay_parent).await?; ensure_i_am_an_authority(keystore, &authorities).await?; let num = authorities.len(); @@ -185,8 +199,13 @@ impl State { let failures = failures.await.unwrap_or(num); self.last_session_index = Some(new_session); - // issue another request if at least a third of the authorities were not resolved - self.force_request = failures >= num / 3; + // issue another request for the same session + // if at least a third of the authorities were not resolved + self.last_failure = if failures >= num / 3 { + Some(Instant::now()) + } else { + None + } } } diff --git a/polkadot/node/network/gossip-support/src/tests.rs b/polkadot/node/network/gossip-support/src/tests.rs index 4d4c6abb5d..72b71d0d65 100644 --- a/polkadot/node/network/gossip-support/src/tests.rs +++ b/polkadot/node/network/gossip-support/src/tests.rs @@ -160,7 +160,7 @@ fn issues_a_connection_request_on_new_session() { }); assert_eq!(state.last_session_index, Some(1)); - assert!(!state.force_request); + assert!(state.last_failure.is_none()); // does not issue on the same session let hash = Hash::repeat_byte(0xBB); @@ -181,7 +181,7 @@ fn issues_a_connection_request_on_new_session() { }); assert_eq!(state.last_session_index, Some(1)); - assert!(!state.force_request); + assert!(state.last_failure.is_none()); // does on the new one let hash = Hash::repeat_byte(0xCC); @@ -225,13 +225,13 @@ fn issues_a_connection_request_on_new_session() { virtual_overseer }); assert_eq!(state.last_session_index, Some(2)); - assert!(!state.force_request); + assert!(state.last_failure.is_none()); } #[test] fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { let hash = Hash::repeat_byte(0xAA); - let state = test_harness(State::default(), |mut virtual_overseer| async move { + let mut state = test_harness(State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; overseer_signal_active_leaves(overseer, hash).await; assert_matches!( @@ -271,7 +271,8 @@ fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { }); assert_eq!(state.last_session_index, Some(1)); - assert!(state.force_request); + assert!(state.last_failure.is_some()); + state.last_failure = state.last_failure.and_then(|i| i.checked_sub(BACKOFF_DURATION)); let hash = Hash::repeat_byte(0xBB); let state = test_harness(state, |mut virtual_overseer| async move { @@ -314,6 +315,6 @@ fn issues_a_connection_request_when_last_request_was_mostly_unresolved() { }); assert_eq!(state.last_session_index, Some(1)); - assert!(!state.force_request); + assert!(state.last_failure.is_none()); }