diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs
index 6f39a5c504d078608038cfb29345b85f07f0835c..406f1130590902f12caa9058c55a80b0fbb54c8a 100644
--- a/polkadot/node/network/statement-distribution/src/v2/mod.rs
+++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs
@@ -142,8 +142,27 @@ struct PerRelayParentState {
 	session: SessionIndex,
 }
 
+impl PerRelayParentState {
+	fn active_validator_state(&self) -> Option<&ActiveValidatorState> {
+		self.local_validator.as_ref().and_then(|local| local.active.as_ref())
+	}
+
+	fn active_validator_state_mut(&mut self) -> Option<&mut ActiveValidatorState> {
+		self.local_validator.as_mut().and_then(|local| local.active.as_mut())
+	}
+}
+
 // per-relay-parent local validator state.
 struct LocalValidatorState {
+	// the grid-level communication at this relay-parent.
+	grid_tracker: GridTracker,
+	// additional fields in case local node is an active validator.
+	active: Option<ActiveValidatorState>,
+	// local index actually exists in case node is inactive validator, however,
+	// it's not needed outside of `build_session_topology`, where it's known.
+}
+
+struct ActiveValidatorState {
 	// The index of the validator.
 	index: ValidatorIndex,
 	// our validator group
@@ -152,8 +171,14 @@ struct LocalValidatorState {
 	assignment: Option<ParaId>,
 	// the 'direct-in-group' communication at this relay-parent.
 	cluster_tracker: ClusterTracker,
-	// the grid-level communication at this relay-parent.
-	grid_tracker: GridTracker,
+}
+
+#[derive(Debug, Copy, Clone)]
+enum LocalValidatorIndex {
+	// Local node is an active validator.
+	Active(ValidatorIndex),
+	// Local node is not in active validator set.
+	Inactive,
 }
 
 #[derive(Debug)]
@@ -164,7 +189,7 @@ struct PerSessionState {
 	// is only `None` in the time between seeing a session and
 	// getting the topology from the gossip-support subsystem
 	grid_view: Option<grid::SessionTopologyView>,
-	local_validator: Option<ValidatorIndex>,
+	local_validator: Option<LocalValidatorIndex>,
 }
 
 impl PerSessionState {
@@ -178,15 +203,10 @@ impl PerSessionState {
 		let local_validator = polkadot_node_subsystem_util::signing_key_and_index(
 			session_info.validators.iter(),
 			keystore,
-		);
+		)
+		.map(|(_, index)| LocalValidatorIndex::Active(index));
 
-		PerSessionState {
-			session_info,
-			groups,
-			authority_lookup,
-			grid_view: None,
-			local_validator: local_validator.map(|(_key, index)| index),
-		}
+		PerSessionState { session_info, groups, authority_lookup, grid_view: None, local_validator }
 	}
 
 	fn supply_topology(
@@ -204,6 +224,16 @@ impl PerSessionState {
 		);
 
 		self.grid_view = Some(grid_view);
+		if local_index.is_some() {
+			self.local_validator.get_or_insert(LocalValidatorIndex::Inactive);
+		}
+	}
+
+	/// Returns `true` if local is neither active or inactive validator node.
+	///
+	/// `false` is also returned if session topology is not known yet.
+	fn is_not_validator(&self) -> bool {
+		self.grid_view.is_some() && self.local_validator.is_none()
 	}
 }
 
@@ -554,13 +584,17 @@ pub(crate) async fn handle_active_leaves_update<Context>(
 			.expect("either existed or just inserted; qed");
 
 		let local_validator = per_session.local_validator.and_then(|v| {
-			find_local_validator_state(
-				v,
-				&per_session.groups,
-				&availability_cores,
-				&group_rotation_info,
-				seconding_limit,
-			)
+			if let LocalValidatorIndex::Active(idx) = v {
+				find_active_validator_state(
+					idx,
+					&per_session.groups,
+					&availability_cores,
+					&group_rotation_info,
+					seconding_limit,
+				)
+			} else {
+				Some(LocalValidatorState { grid_tracker: GridTracker::default(), active: None })
+			}
 		});
 
 		state.per_relay_parent.insert(
@@ -607,7 +641,7 @@ pub(crate) async fn handle_active_leaves_update<Context>(
 	Ok(())
 }
 
-fn find_local_validator_state(
+fn find_active_validator_state(
 	validator_index: ValidatorIndex,
 	groups: &Groups,
 	availability_cores: &[CoreState],
@@ -628,11 +662,13 @@ fn find_local_validator_state(
 	let group_validators = groups.get(our_group)?.to_owned();
 
 	Some(LocalValidatorState {
-		index: validator_index,
-		group: our_group,
-		assignment: para,
-		cluster_tracker: ClusterTracker::new(group_validators, seconding_limit)
-			.expect("group is non-empty because we are in it; qed"),
+		active: Some(ActiveValidatorState {
+			index: validator_index,
+			group: our_group,
+			assignment: para,
+			cluster_tracker: ClusterTracker::new(group_validators, seconding_limit)
+				.expect("group is non-empty because we are in it; qed"),
+		}),
 		grid_tracker: GridTracker::default(),
 	})
 }
@@ -725,13 +761,17 @@ async fn send_peer_messages_for_relay_parent<Context>(
 	for validator_id in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| {
 		per_session_state.authority_lookup.get(a)
 	}) {
-		if let Some(local_validator_state) = relay_parent_state.local_validator.as_mut() {
+		if let Some(active) = relay_parent_state
+			.local_validator
+			.as_mut()
+			.and_then(|local| local.active.as_mut())
+		{
 			send_pending_cluster_statements(
 				ctx,
 				relay_parent,
 				&(peer, peer_data.protocol_version),
 				validator_id,
-				&mut local_validator_state.cluster_tracker,
+				&mut active.cluster_tracker,
 				&state.candidates,
 				&relay_parent_state.statement_store,
 			)
@@ -1009,7 +1049,7 @@ pub(crate) async fn share_local_statement<Context>(
 	};
 
 	let (local_index, local_assignment, local_group) =
-		match per_relay_parent.local_validator.as_ref() {
+		match per_relay_parent.active_validator_state() {
 			None => return Err(JfyiError::InvalidShare),
 			Some(l) => (l.index, l.assignment, l.group),
 		};
@@ -1086,7 +1126,7 @@ pub(crate) async fn share_local_statement<Context>(
 		}
 
 		{
-			let l = per_relay_parent.local_validator.as_mut().expect("checked above; qed");
+			let l = per_relay_parent.active_validator_state_mut().expect("checked above; qed");
 			l.cluster_tracker.note_issued(local_index, compact_statement.payload().clone());
 		}
 
@@ -1173,31 +1213,41 @@ async fn circulate_statement<Context>(
 
 		// We're not meant to circulate statements in the cluster until we have the confirmed
 		// candidate.
-		let cluster_relevant = Some(local_validator.group) == statement_group;
-		let cluster_targets = if is_confirmed && cluster_relevant {
-			Some(
-				local_validator
-					.cluster_tracker
-					.targets()
-					.iter()
-					.filter(|&&v| {
-						local_validator
+		//
+		// Cluster is only relevant if local node is an active validator.
+		let (cluster_relevant, cluster_targets, all_cluster_targets) = local_validator
+			.active
+			.as_mut()
+			.map(|active| {
+				let cluster_relevant = Some(active.group) == statement_group;
+				let cluster_targets = if is_confirmed && cluster_relevant {
+					Some(
+						active
 							.cluster_tracker
-							.can_send(v, originator, compact_statement.clone())
-							.is_ok()
-					})
-					.filter(|&v| v != &local_validator.index)
-					.map(|v| (*v, DirectTargetKind::Cluster)),
-			)
-		} else {
-			None
-		};
+							.targets()
+							.iter()
+							.filter(|&&v| {
+								active
+									.cluster_tracker
+									.can_send(v, originator, compact_statement.clone())
+									.is_ok()
+							})
+							.filter(|&v| v != &active.index)
+							.map(|v| (*v, DirectTargetKind::Cluster)),
+					)
+				} else {
+					None
+				};
+				let all_cluster_targets = active.cluster_tracker.targets();
+				(cluster_relevant, cluster_targets, all_cluster_targets)
+			})
+			.unwrap_or((false, None, &[]));
 
 		let grid_targets = local_validator
 			.grid_tracker
 			.direct_statement_targets(&per_session.groups, originator, &compact_statement)
 			.into_iter()
-			.filter(|v| !cluster_relevant || !local_validator.cluster_tracker.targets().contains(v))
+			.filter(|v| !cluster_relevant || !all_cluster_targets.contains(v))
 			.map(|v| (v, DirectTargetKind::Grid));
 
 		let targets = cluster_targets
@@ -1229,18 +1279,17 @@ async fn circulate_statement<Context>(
 
 		match kind {
 			DirectTargetKind::Cluster => {
+				let active = local_validator
+					.active
+					.as_mut()
+					.expect("cluster target means local is active validator; qed");
+
 				// At this point, all peers in the cluster should 'know'
 				// the candidate, so we don't expect for this to fail.
-				if let Ok(()) = local_validator.cluster_tracker.can_send(
-					target,
-					originator,
-					compact_statement.clone(),
-				) {
-					local_validator.cluster_tracker.note_sent(
-						target,
-						originator,
-						compact_statement.clone(),
-					);
+				if let Ok(()) =
+					active.cluster_tracker.can_send(target, originator, compact_statement.clone())
+				{
+					active.cluster_tracker.note_sent(target, originator, compact_statement.clone());
 					statement_to_peers.push(peer_id);
 				}
 			},
@@ -1387,7 +1436,9 @@ async fn handle_incoming_statement<Context>(
 		None => {
 			// we shouldn't be receiving statements unless we're a validator
 			// this session.
-			modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await;
+			if per_session.is_not_validator() {
+				modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await;
+			}
 			return
 		},
 		Some(l) => l,
@@ -1402,73 +1453,81 @@ async fn handle_incoming_statement<Context>(
 			},
 		};
 
-	let cluster_sender_index = {
+	let (active, cluster_sender_index) = {
 		// This block of code only returns `Some` when both the originator and
 		// the sending peer are in the cluster.
+		let active = local_validator.active.as_mut();
 
-		let allowed_senders = local_validator
-			.cluster_tracker
-			.senders_for_originator(statement.unchecked_validator_index());
+		let allowed_senders = active
+			.as_ref()
+			.map(|active| {
+				active
+					.cluster_tracker
+					.senders_for_originator(statement.unchecked_validator_index())
+			})
+			.unwrap_or_default();
 
-		allowed_senders
+		let idx = allowed_senders
 			.iter()
 			.filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (*i, ad)))
 			.filter(|(_, ad)| peer_state.is_authority(ad))
 			.map(|(i, _)| i)
-			.next()
-	};
-
-	let checked_statement = if let Some(cluster_sender_index) = cluster_sender_index {
-		match handle_cluster_statement(
-			relay_parent,
-			&mut local_validator.cluster_tracker,
-			per_relay_parent.session,
-			&per_session.session_info,
-			statement,
-			cluster_sender_index,
-		) {
-			Ok(Some(s)) => s,
-			Ok(None) => return,
-			Err(rep) => {
-				modify_reputation(reputation, ctx.sender(), peer, rep).await;
-				return
-			},
-		}
-	} else {
-		let grid_sender_index = local_validator
-			.grid_tracker
-			.direct_statement_providers(
-				&per_session.groups,
-				statement.unchecked_validator_index(),
-				statement.unchecked_payload(),
-			)
-			.into_iter()
-			.filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (i, ad)))
-			.filter(|(_, ad)| peer_state.is_authority(ad))
-			.map(|(i, _)| i)
 			.next();
+		(active, idx)
+	};
 
-		if let Some(grid_sender_index) = grid_sender_index {
-			match handle_grid_statement(
+	let checked_statement =
+		if let Some((active, cluster_sender_index)) = active.zip(cluster_sender_index) {
+			match handle_cluster_statement(
 				relay_parent,
-				&mut local_validator.grid_tracker,
+				&mut active.cluster_tracker,
 				per_relay_parent.session,
-				&per_session,
+				&per_session.session_info,
 				statement,
-				grid_sender_index,
+				cluster_sender_index,
 			) {
-				Ok(s) => s,
+				Ok(Some(s)) => s,
+				Ok(None) => return,
 				Err(rep) => {
 					modify_reputation(reputation, ctx.sender(), peer, rep).await;
 					return
 				},
 			}
 		} else {
-			// Not a cluster or grid peer.
-			modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await;
-			return
-		}
-	};
+			let grid_sender_index = local_validator
+				.grid_tracker
+				.direct_statement_providers(
+					&per_session.groups,
+					statement.unchecked_validator_index(),
+					statement.unchecked_payload(),
+				)
+				.into_iter()
+				.filter_map(|i| session_info.discovery_keys.get(i.0 as usize).map(|ad| (i, ad)))
+				.filter(|(_, ad)| peer_state.is_authority(ad))
+				.map(|(i, _)| i)
+				.next();
+
+			if let Some(grid_sender_index) = grid_sender_index {
+				match handle_grid_statement(
+					relay_parent,
+					&mut local_validator.grid_tracker,
+					per_relay_parent.session,
+					&per_session,
+					statement,
+					grid_sender_index,
+				) {
+					Ok(s) => s,
+					Err(rep) => {
+						modify_reputation(reputation, ctx.sender(), peer, rep).await;
+						return
+					},
+				}
+			} else {
+				// Not a cluster or grid peer.
+				modify_reputation(reputation, ctx.sender(), peer, COST_UNEXPECTED_STATEMENT).await;
+				return
+			}
+		};
 
 	let statement = checked_statement.payload().clone();
 	let originator_index = checked_statement.validator_index();
@@ -1536,7 +1595,7 @@ async fn handle_incoming_statement<Context>(
 			local_validator.grid_tracker.learned_fresh_statement(
 				&per_session.groups,
 				session_topology,
-				local_validator.index,
+				originator_index,
 				&statement,
 			);
 		}
@@ -1834,7 +1893,7 @@ async fn provide_candidate_to_grid<Context>(
 		gum::debug!(
 			target: LOG_TARGET,
 			?candidate_hash,
-			local_validator = ?local_validator.index,
+			local_validator = ?per_session.local_validator,
 			n_peers = manifest_peers_v2.len(),
 			"Sending manifest to v2 peers"
 		);
@@ -1853,7 +1912,7 @@ async fn provide_candidate_to_grid<Context>(
 		gum::debug!(
 			target: LOG_TARGET,
 			?candidate_hash,
-			local_validator = ?local_validator.index,
+			local_validator = ?per_session.local_validator,
 			n_peers = manifest_peers_vstaging.len(),
 			"Sending manifest to vstaging peers"
 		);
@@ -1874,7 +1933,7 @@ async fn provide_candidate_to_grid<Context>(
 		gum::debug!(
 			target: LOG_TARGET,
 			?candidate_hash,
-			local_validator = ?local_validator.index,
+			local_validator = ?per_session.local_validator,
 			n_peers = ack_peers_v2.len(),
 			"Sending acknowledgement to v2 peers"
 		);
@@ -1893,7 +1952,7 @@ async fn provide_candidate_to_grid<Context>(
 		gum::debug!(
 			target: LOG_TARGET,
 			?candidate_hash,
-			local_validator = ?local_validator.index,
+			local_validator = ?per_session.local_validator,
 			n_peers = ack_peers_vstaging.len(),
 			"Sending acknowledgement to vstaging peers"
 		);
@@ -2086,13 +2145,15 @@ async fn handle_incoming_manifest_common<'a, Context>(
 
 	let local_validator = match relay_parent_state.local_validator.as_mut() {
 		None => {
-			modify_reputation(
-				reputation,
-				ctx.sender(),
-				peer,
-				COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE,
-			)
-			.await;
+			if per_session.is_not_validator() {
+				modify_reputation(
+					reputation,
+					ctx.sender(),
+					peer,
+					COST_UNEXPECTED_MANIFEST_MISSING_KNOWLEDGE,
+				)
+				.await;
+			}
 			return None
 		},
 		Some(x) => x,
@@ -2188,7 +2249,7 @@ async fn handle_incoming_manifest_common<'a, Context>(
 			target: LOG_TARGET,
 			?candidate_hash,
 			from = ?sender_index,
-			local_index = ?local_validator.index,
+			local_index = ?per_session.local_validator,
 			?manifest_kind,
 			"immediate ack, known candidate"
 		);
@@ -2593,7 +2654,7 @@ async fn send_cluster_candidate_statements<Context>(
 		Some(s) => s,
 	};
 
-	let local_group = match relay_parent_state.local_validator.as_mut() {
+	let local_group = match relay_parent_state.active_validator_state_mut() {
 		None => return,
 		Some(v) => v.group,
 	};
@@ -2680,11 +2741,10 @@ pub(crate) async fn dispatch_requests<Context>(ctx: &mut Context, state: &mut St
 		}) {
 			// For cluster members, they haven't advertised any statements in particular,
 			// but have surely sent us some.
-			if local_validator
-				.cluster_tracker
-				.knows_candidate(validator_id, identifier.candidate_hash)
-			{
-				return Some(StatementFilter::blank(local_validator.cluster_tracker.targets().len()))
+			if let Some(active) = local_validator.active.as_ref() {
+				if active.cluster_tracker.knows_candidate(validator_id, identifier.candidate_hash) {
+					return Some(StatementFilter::blank(active.cluster_tracker.targets().len()))
+				}
 			}
 
 			let filter = local_validator
@@ -2715,7 +2775,11 @@ pub(crate) async fn dispatch_requests<Context>(ctx: &mut Context, state: &mut St
 		}
 
 		// don't require a backing threshold for cluster candidates.
-		let require_backing = relay_parent_state.local_validator.as_ref()?.group != group_index;
+		let local_validator = relay_parent_state.local_validator.as_ref()?;
+		let require_backing = local_validator
+			.active
+			.as_ref()
+			.map_or(true, |active| active.group != group_index);
 
 		Some(RequestProperties {
 			unwanted_mask,
@@ -2973,7 +3037,11 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) {
 		for v in find_validator_ids(peer_data.iter_known_discovery_ids(), |a| {
 			per_session.authority_lookup.get(a)
 		}) {
-			if local_validator.cluster_tracker.can_request(v, *candidate_hash) {
+			if local_validator
+				.active
+				.as_ref()
+				.map_or(false, |active| active.cluster_tracker.can_request(v, *candidate_hash))
+			{
 				validator_id = Some(v);
 				is_cluster = true;
 				break
@@ -3015,11 +3083,16 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) {
 	// Update bookkeeping about which statements peers have received.
 	for statement in &statements {
 		if is_cluster {
-			local_validator.cluster_tracker.note_sent(
-				validator_id,
-				statement.unchecked_validator_index(),
-				statement.unchecked_payload().clone(),
-			);
+			local_validator
+				.active
+				.as_mut()
+				.expect("cluster peer means local is active validator; qed")
+				.cluster_tracker
+				.note_sent(
+					validator_id,
+					statement.unchecked_validator_index(),
+					statement.unchecked_payload().clone(),
+				);
 		} else {
 			local_validator.grid_tracker.sent_or_received_direct_statement(
 				&per_session.groups,
diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs
index 80dec1d75ab98be43b820bf7382b4436ef87c3b2..a9f5b537b3238ab8b13ff37a0e952b35ba92a066 100644
--- a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs
+++ b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs
@@ -23,7 +23,7 @@ fn share_seconded_circulated_to_cluster() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -34,7 +34,8 @@ fn share_seconded_circulated_to_cluster() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -52,7 +53,7 @@ fn share_seconded_circulated_to_cluster() {
 		// peer B is in group, has no relay parent in view.
 		// peer C is not in group, has relay parent in view.
 		{
-			let other_group_validators = state.group_validators(local_validator.group_index, true);
+			let other_group_validators = state.group_validators(local_group_index, true);
 
 			connect_peer(
 				&mut overseer,
@@ -130,7 +131,7 @@ fn cluster_valid_statement_before_seconded_ignored() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -139,12 +140,13 @@ fn cluster_valid_statement_before_seconded_ignored() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 		let candidate_hash = CandidateHash(Hash::repeat_byte(42));
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
 		// peer A is in group, has relay parent in view.
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 		connect_peer(
 			&mut overseer,
@@ -197,7 +199,7 @@ fn cluster_statement_bad_signature() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -206,12 +208,13 @@ fn cluster_statement_bad_signature() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 		let candidate_hash = CandidateHash(Hash::repeat_byte(42));
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
 		// peer A is in group, has relay parent in view.
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
 
@@ -277,7 +280,7 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -286,13 +289,13 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 		let candidate_hash = CandidateHash(Hash::repeat_byte(42));
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
 		// peer A is not in group, has relay parent in view.
-		let not_our_group =
-			if local_validator.group_index.0 == 0 { GroupIndex(1) } else { GroupIndex(0) };
+		let not_our_group = if local_group_index.0 == 0 { GroupIndex(1) } else { GroupIndex(0) };
 
 		let that_group_validators = state.group_validators(not_our_group, false);
 		let v_non = that_group_validators[0];
@@ -346,7 +349,7 @@ fn statement_from_non_cluster_originator_unexpected() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -355,12 +358,13 @@ fn statement_from_non_cluster_originator_unexpected() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 		let candidate_hash = CandidateHash(Hash::repeat_byte(42));
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
 		// peer A is not in group, has relay parent in view.
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 
 		connect_peer(&mut overseer, peer_a.clone(), None).await;
@@ -408,7 +412,7 @@ fn seconded_statement_leads_to_request() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -417,7 +421,8 @@ fn seconded_statement_leads_to_request() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -432,7 +437,7 @@ fn seconded_statement_leads_to_request() {
 		let candidate_hash = candidate.hash();
 
 		// peer A is in group, has relay parent in view.
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 
 		connect_peer(
@@ -503,7 +508,7 @@ fn cluster_statements_shared_seconded_first() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -512,7 +517,8 @@ fn cluster_statements_shared_seconded_first() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -528,7 +534,7 @@ fn cluster_statements_shared_seconded_first() {
 
 		// peer A is in group, no relay parent in view.
 		{
-			let other_group_validators = state.group_validators(local_validator.group_index, true);
+			let other_group_validators = state.group_validators(local_group_index, true);
 
 			connect_peer(
 				&mut overseer,
@@ -624,7 +630,7 @@ fn cluster_accounts_for_implicit_view() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -634,7 +640,8 @@ fn cluster_accounts_for_implicit_view() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -651,7 +658,7 @@ fn cluster_accounts_for_implicit_view() {
 		// peer A is in group, has relay parent in view.
 		// peer B is in group, has no relay parent in view.
 		{
-			let other_group_validators = state.group_validators(local_validator.group_index, true);
+			let other_group_validators = state.group_validators(local_group_index, true);
 
 			connect_peer(
 				&mut overseer,
@@ -775,7 +782,7 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -784,7 +791,8 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -799,7 +807,7 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() {
 		let candidate_hash = candidate.hash();
 
 		// peer A is in group, has relay parent in view.
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 		{
 			connect_peer(
@@ -907,7 +915,7 @@ fn cluster_messages_imported_after_new_leaf_importable_check() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -916,7 +924,8 @@ fn cluster_messages_imported_after_new_leaf_importable_check() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -931,7 +940,7 @@ fn cluster_messages_imported_after_new_leaf_importable_check() {
 		let candidate_hash = candidate.hash();
 
 		// peer A is in group, has relay parent in view.
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 		{
 			connect_peer(
@@ -1048,7 +1057,7 @@ fn ensure_seconding_limit_is_respected() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 4,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: Some(AsyncBackingParams {
 			max_candidate_depth: 1,
 			allowed_ancestry_len: 3,
@@ -1060,7 +1069,8 @@ fn ensure_seconding_limit_is_respected() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -1092,7 +1102,7 @@ fn ensure_seconding_limit_is_respected() {
 		let candidate_hash_2 = candidate_2.hash();
 		let candidate_hash_3 = candidate_3.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 
 		// peers A,B,C are in group, have relay parent in view.
diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs
index 5b1dabfc8a0e3a9690be131d5abb27cc78750866..9802db060821407ef9c14650701ef3a82a74f858 100644
--- a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs
+++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs
@@ -29,7 +29,7 @@ fn backed_candidate_leads_to_advertisement() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -41,7 +41,8 @@ fn backed_candidate_leads_to_advertisement() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -55,9 +56,9 @@ fn backed_candidate_leads_to_advertisement() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let target_group_validators =
-			state.group_validators((local_validator.group_index.0 + 1).into(), true);
+			state.group_validators((local_group_index.0 + 1).into(), true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
 		let v_c = target_group_validators[0];
@@ -219,7 +220,7 @@ fn backed_candidate_leads_to_advertisement() {
 					assert_eq!(manifest, BackedCandidateManifest {
 						relay_parent,
 						candidate_hash,
-						group_index: local_validator.group_index,
+						group_index: local_group_index,
 						para_id: local_para,
 						parent_head_data_hash: pvd.parent_head.hash(),
 						statement_knowledge: StatementFilter {
@@ -244,7 +245,7 @@ fn received_advertisement_before_confirmation_leads_to_request() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -256,9 +257,9 @@ fn received_advertisement_before_confirmation_leads_to_request() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -273,7 +274,7 @@ fn received_advertisement_before_confirmation_leads_to_request() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let target_group_validators = state.group_validators(other_group, true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
@@ -424,7 +425,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -435,9 +436,9 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -672,7 +673,7 @@ fn received_advertisement_after_confirmation_before_backing() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -683,9 +684,9 @@ fn received_advertisement_after_confirmation_before_backing() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -858,7 +859,7 @@ fn additional_statements_are_shared_after_manifest_exchange() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -869,9 +870,9 @@ fn additional_statements_are_shared_after_manifest_exchange() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -1155,7 +1156,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1167,7 +1168,8 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -1181,9 +1183,9 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let target_group_validators =
-			state.group_validators((local_validator.group_index.0 + 1).into(), true);
+			state.group_validators((local_group_index.0 + 1).into(), true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
 		let v_c = target_group_validators[0];
@@ -1336,7 +1338,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() {
 			let expected_manifest = BackedCandidateManifest {
 				relay_parent,
 				candidate_hash,
-				group_index: local_validator.group_index,
+				group_index: local_group_index,
 				para_id: local_para,
 				parent_head_data_hash: pvd.parent_head.hash(),
 				statement_knowledge: StatementFilter {
@@ -1377,7 +1379,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1389,7 +1391,8 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -1403,9 +1406,9 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let target_group_validators =
-			state.group_validators((local_validator.group_index.0 + 1).into(), true);
+			state.group_validators((local_group_index.0 + 1).into(), true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
 		let v_c = target_group_validators[0];
@@ -1567,7 +1570,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() {
 					assert_eq!(manifest, BackedCandidateManifest {
 						relay_parent,
 						candidate_hash,
-						group_index: local_validator.group_index,
+						group_index: local_group_index,
 						para_id: local_para,
 						parent_head_data_hash: pvd.parent_head.hash(),
 						statement_knowledge: StatementFilter {
@@ -1599,7 +1602,7 @@ fn grid_statements_imported_to_backing() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1610,9 +1613,9 @@ fn grid_statements_imported_to_backing() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -1803,7 +1806,7 @@ fn advertisements_rejected_from_incorrect_peers() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1815,9 +1818,9 @@ fn advertisements_rejected_from_incorrect_peers() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -1832,12 +1835,12 @@ fn advertisements_rejected_from_incorrect_peers() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let target_group_validators = state.group_validators(local_validator.group_index, true);
-		let other_group_validators = state.group_validators(other_group, true);
-		let v_a = target_group_validators[0];
-		let v_b = target_group_validators[1];
-		let v_c = other_group_validators[0];
-		let v_d = other_group_validators[1];
+		let other_group_validators = state.group_validators(local_group_index, true);
+		let target_group_validators = state.group_validators(other_group, true);
+		let v_a = other_group_validators[0];
+		let v_b = other_group_validators[1];
+		let v_c = target_group_validators[0];
+		let v_d = target_group_validators[1];
 
 		// peer A is in group, has relay parent in view.
 		// peer B is in group, has no relay parent in view.
@@ -1948,7 +1951,7 @@ fn manifest_rejected_with_unknown_relay_parent() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1959,9 +1962,9 @@ fn manifest_rejected_with_unknown_relay_parent() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -2054,7 +2057,7 @@ fn manifest_rejected_when_not_a_validator() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: false,
+		local_validator: LocalRole::None,
 		async_backing_params: None,
 	};
 
@@ -2156,7 +2159,7 @@ fn manifest_rejected_when_group_does_not_match_para() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -2166,9 +2169,9 @@ fn manifest_rejected_when_group_does_not_match_para() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		// Create a mismatch between group and para.
 		let other_para = next_group_index(other_group, validator_count, group_size);
 		let other_para = ParaId::from(other_para.0);
@@ -2263,7 +2266,7 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -2274,9 +2277,9 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -2454,3 +2457,141 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() {
 		overseer
 	});
 }
+
+#[test]
+fn inactive_local_participates_in_grid() {
+	let validator_count = 11;
+	let group_size = 3;
+	let config = TestConfig {
+		validator_count,
+		group_size,
+		local_validator: LocalRole::InactiveValidator,
+		async_backing_params: None,
+	};
+
+	let dummy_relay_parent = Hash::repeat_byte(2);
+	let relay_parent = Hash::repeat_byte(1);
+	let peer_a = PeerId::random();
+
+	test_harness(config, |state, mut overseer| async move {
+		let local_validator = state.local.clone().unwrap();
+		assert_eq!(local_validator.validator_index.0, validator_count as u32);
+
+		let group_idx = GroupIndex::from(0);
+		let para = ParaId::from(0);
+
+		// Dummy leaf is needed to update topology.
+		let dummy_leaf = state.make_dummy_leaf(Hash::repeat_byte(2));
+		let test_leaf = state.make_dummy_leaf(relay_parent);
+
+		let (candidate, pvd) = make_candidate(
+			relay_parent,
+			1,
+			para,
+			test_leaf.para_data(para).head_data.clone(),
+			vec![4, 5, 6].into(),
+			Hash::repeat_byte(42).into(),
+		);
+		let candidate_hash = candidate.hash();
+
+		let first_group = state.group_validators(group_idx, true);
+		let v_a = first_group.last().unwrap().clone();
+		let v_b = first_group.first().unwrap().clone();
+
+		{
+			connect_peer(
+				&mut overseer,
+				peer_a.clone(),
+				Some(vec![state.discovery_id(v_a)].into_iter().collect()),
+			)
+			.await;
+
+			send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await;
+		}
+
+		activate_leaf(&mut overseer, &dummy_leaf, &state, true).await;
+		answer_expected_hypothetical_depth_request(
+			&mut overseer,
+			vec![],
+			Some(dummy_relay_parent),
+			false,
+		)
+		.await;
+
+		// Send gossip topology.
+		send_new_topology(&mut overseer, state.make_dummy_topology()).await;
+		activate_leaf(&mut overseer, &test_leaf, &state, false).await;
+		answer_expected_hypothetical_depth_request(
+			&mut overseer,
+			vec![],
+			Some(relay_parent),
+			false,
+		)
+		.await;
+
+		// Receive an advertisement from A.
+		let manifest = BackedCandidateManifest {
+			relay_parent,
+			candidate_hash,
+			group_index: group_idx,
+			para_id: para,
+			parent_head_data_hash: pvd.parent_head.hash(),
+			statement_knowledge: StatementFilter {
+				seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1],
+				validated_in_group: bitvec::bitvec![u8, Lsb0; 1, 0, 1],
+			},
+		};
+		send_peer_message(
+			&mut overseer,
+			peer_a.clone(),
+			protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest),
+		)
+		.await;
+
+		let statements = vec![
+			state
+				.sign_statement(
+					v_a,
+					CompactStatement::Seconded(candidate_hash),
+					&SigningContext { parent_hash: relay_parent, session_index: 1 },
+				)
+				.as_unchecked()
+				.clone(),
+			state
+				.sign_statement(
+					v_b,
+					CompactStatement::Seconded(candidate_hash),
+					&SigningContext { parent_hash: relay_parent, session_index: 1 },
+				)
+				.as_unchecked()
+				.clone(),
+		];
+		// Inactive node requests this candidate.
+		handle_sent_request(
+			&mut overseer,
+			peer_a,
+			candidate_hash,
+			StatementFilter::blank(group_size),
+			candidate.clone(),
+			pvd.clone(),
+			statements,
+		)
+		.await;
+
+		for _ in 0..2 {
+			assert_matches!(
+				overseer.recv().await,
+				AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r)))
+					if p == peer_a && r == BENEFIT_VALID_STATEMENT.into() => { }
+			);
+		}
+		assert_matches!(
+			overseer.recv().await,
+			AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r)))
+				if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { }
+		);
+		answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await;
+
+		overseer
+	});
+}
diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs
index 4150377a0c6c219832104024f6d6c046dccec709..4e6269775245dde88f9debd19c60dce9717c09af 100644
--- a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs
+++ b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs
@@ -61,19 +61,30 @@ const DEFAULT_ASYNC_BACKING_PARAMETERS: AsyncBackingParams =
 // Some deterministic genesis hash for req/res protocol names
 const GENESIS_HASH: Hash = Hash::repeat_byte(0xff);
 
+#[derive(Debug, Copy, Clone)]
+enum LocalRole {
+	/// Active validator.
+	Validator,
+	/// Authority, not in active validator set.
+	InactiveValidator,
+	/// Not a validator.
+	None,
+}
+
 struct TestConfig {
+	// number of active validators.
 	validator_count: usize,
 	// how many validators to place in each group.
 	group_size: usize,
 	// whether the local node should be a validator
-	local_validator: bool,
+	local_validator: LocalRole,
 	async_backing_params: Option<AsyncBackingParams>,
 }
 
 #[derive(Debug, Clone)]
 struct TestLocalValidator {
 	validator_index: ValidatorIndex,
-	group_index: GroupIndex,
+	group_index: Option<GroupIndex>,
 }
 
 struct TestState {
@@ -99,7 +110,7 @@ impl TestState {
 		let mut assignment_keys = Vec::new();
 		let mut validator_groups = Vec::new();
 
-		let local_validator_pos = if config.local_validator {
+		let local_validator_pos = if let LocalRole::Validator = config.local_validator {
 			// ensure local validator is always in a full group.
 			Some(rng.gen_range(0..config.validator_count).saturating_sub(config.group_size - 1))
 		} else {
@@ -128,13 +139,19 @@ impl TestState {
 			}
 		}
 
-		let local = if let Some(local_pos) = local_validator_pos {
-			Some(TestLocalValidator {
+		let local = match (config.local_validator, local_validator_pos) {
+			(LocalRole::Validator, Some(local_pos)) => Some(TestLocalValidator {
 				validator_index: ValidatorIndex(local_pos as _),
-				group_index: GroupIndex((local_pos / config.group_size) as _),
-			})
-		} else {
-			None
+				group_index: Some(GroupIndex((local_pos / config.group_size) as _)),
+			}),
+			(LocalRole::InactiveValidator, None) => {
+				discovery_keys.push(AuthorityDiscoveryPair::generate().0.public());
+				Some(TestLocalValidator {
+					validator_index: ValidatorIndex(config.validator_count as u32),
+					group_index: None,
+				})
+			},
+			_ => None,
 		};
 
 		let validator_public = validator_pubkeys(&validators);
@@ -181,15 +198,23 @@ impl TestState {
 
 	fn make_dummy_topology(&self) -> NewGossipTopology {
 		let validator_count = self.config.validator_count;
+		let is_local_inactive = matches!(self.config.local_validator, LocalRole::InactiveValidator);
+
+		let mut indices: Vec<usize> = (0..validator_count).collect();
+		if is_local_inactive {
+			indices.push(validator_count);
+		}
+
 		NewGossipTopology {
 			session: 1,
 			topology: SessionGridTopology::new(
-				(0..validator_count).collect(),
-				(0..validator_count)
+				indices.clone(),
+				indices
+					.into_iter()
 					.map(|i| TopologyPeerInfo {
 						peer_ids: Vec::new(),
 						validator_index: ValidatorIndex(i as u32),
-						discovery_id: AuthorityDiscoveryPair::generate().0.public(),
+						discovery_id: self.session_info.discovery_keys[i].clone(),
 					})
 					.collect(),
 			),
@@ -276,7 +301,7 @@ fn test_harness<T: Future<Output = VirtualOverseer>>(
 	test: impl FnOnce(TestState, VirtualOverseer) -> T,
 ) {
 	let pool = sp_core::testing::TaskExecutor::new();
-	let keystore = if config.local_validator {
+	let keystore = if let LocalRole::Validator = config.local_validator {
 		test_helpers::mock::make_ferdie_keystore()
 	} else {
 		Arc::new(LocalKeystore::in_memory()) as KeystorePtr
diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs
index 4734d7a0f960bf43cd09a50ceb96c29fa0deadf3..1eec8290fabaeec37c1dea2b53de3d8c32385336 100644
--- a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs
+++ b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs
@@ -32,7 +32,7 @@ fn cluster_peer_allowed_to_send_incomplete_statements() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -43,7 +43,8 @@ fn cluster_peer_allowed_to_send_incomplete_statements() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -57,7 +58,7 @@ fn cluster_peer_allowed_to_send_incomplete_statements() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
 
@@ -188,7 +189,7 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: Some(AsyncBackingParams {
 			// Makes `seconding_limit: 2` (easier to hit the limit).
 			max_candidate_depth: 1,
@@ -203,9 +204,9 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -475,7 +476,7 @@ fn peer_reported_for_not_enough_statements() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -486,9 +487,9 @@ fn peer_reported_for_not_enough_statements() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
@@ -670,7 +671,7 @@ fn peer_reported_for_duplicate_statements() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -681,7 +682,8 @@ fn peer_reported_for_duplicate_statements() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -695,7 +697,7 @@ fn peer_reported_for_duplicate_statements() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
 
@@ -830,7 +832,7 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -841,7 +843,8 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -855,8 +858,8 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
-		state.group_validators((local_validator.group_index.0 + 1).into(), true);
+		let other_group_validators = state.group_validators(local_group_index, true);
+		state.group_validators((local_group_index.0 + 1).into(), true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
 
@@ -968,7 +971,7 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -979,7 +982,8 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -993,9 +997,8 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
-		let next_group_validators =
-			state.group_validators((local_validator.group_index.0 + 1).into(), true);
+		let other_group_validators = state.group_validators(local_group_index, true);
+		let next_group_validators = state.group_validators((local_group_index.0 + 1).into(), true);
 		let v_a = other_group_validators[0];
 		let v_c = next_group_validators[0];
 
@@ -1105,7 +1108,7 @@ fn local_node_sanity_checks_incoming_requests() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1117,7 +1120,8 @@ fn local_node_sanity_checks_incoming_requests() {
 
 	test_harness(config, |mut state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -1135,7 +1139,7 @@ fn local_node_sanity_checks_incoming_requests() {
 		// peer B is in group, has no relay parent in view.
 		// peer C is not in group, has relay parent in view.
 		{
-			let other_group_validators = state.group_validators(local_validator.group_index, true);
+			let other_group_validators = state.group_validators(local_group_index, true);
 
 			connect_peer(
 				&mut overseer,
@@ -1311,7 +1315,7 @@ fn local_node_checks_that_peer_can_request_before_responding() {
 	let config = TestConfig {
 		validator_count: 20,
 		group_size: 3,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1321,7 +1325,8 @@ fn local_node_checks_that_peer_can_request_before_responding() {
 
 	test_harness(config, |mut state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -1336,7 +1341,7 @@ fn local_node_checks_that_peer_can_request_before_responding() {
 		let candidate_hash = candidate.hash();
 
 		// Peers A and B are in group and have relay parent in view.
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 
 		connect_peer(
 			&mut overseer,
@@ -1515,7 +1520,7 @@ fn local_node_respects_statement_mask() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1527,7 +1532,8 @@ fn local_node_respects_statement_mask() {
 
 	test_harness(config, |mut state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
-		let local_para = ParaId::from(local_validator.group_index.0);
+		let local_group_index = local_validator.group_index.unwrap();
+		let local_para = ParaId::from(local_group_index.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);
 
@@ -1541,9 +1547,9 @@ fn local_node_respects_statement_mask() {
 		);
 		let candidate_hash = candidate.hash();
 
-		let other_group_validators = state.group_validators(local_validator.group_index, true);
+		let other_group_validators = state.group_validators(local_group_index, true);
 		let target_group_validators =
-			state.group_validators((local_validator.group_index.0 + 1).into(), true);
+			state.group_validators((local_group_index.0 + 1).into(), true);
 		let v_a = other_group_validators[0];
 		let v_b = other_group_validators[1];
 		let v_c = target_group_validators[0];
@@ -1707,7 +1713,7 @@ fn local_node_respects_statement_mask() {
 					assert_eq!(manifest, BackedCandidateManifest {
 						relay_parent,
 						candidate_hash,
-						group_index: local_validator.group_index,
+						group_index: local_group_index,
 						para_id: local_para,
 						parent_head_data_hash: pvd.parent_head.hash(),
 						statement_knowledge: StatementFilter {
@@ -1761,7 +1767,7 @@ fn should_delay_before_retrying_dropped_requests() {
 	let config = TestConfig {
 		validator_count,
 		group_size,
-		local_validator: true,
+		local_validator: LocalRole::Validator,
 		async_backing_params: None,
 	};
 
@@ -1772,9 +1778,9 @@ fn should_delay_before_retrying_dropped_requests() {
 
 	test_harness(config, |state, mut overseer| async move {
 		let local_validator = state.local.clone().unwrap();
+		let local_group_index = local_validator.group_index.unwrap();
 
-		let other_group =
-			next_group_index(local_validator.group_index, validator_count, group_size);
+		let other_group = next_group_index(local_group_index, validator_count, group_size);
 		let other_para = ParaId::from(other_group.0);
 
 		let test_leaf = state.make_dummy_leaf(relay_parent);