mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-08-06 23:35:48 +00:00
statement-distribution: validator disabling (#1841)
Closes #1591. The purpose of this PR is filter out backing statements from the network signed by disabled validators. This is just an optimization, since we will do filtering in the runtime in #1863 to avoid nodes to filter garbage out at block production time. - [x] Ensure it's ok to fiddle with the mask of manifests - [x] Write more unit tests - [x] Test locally - [x] simple zombienet test - [x] PRDoc --------- Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io>
This commit is contained in:
@@ -187,12 +187,30 @@ impl TestState {
|
||||
collator: None,
|
||||
})
|
||||
}),
|
||||
disabled_validators: Default::default(),
|
||||
para_data: (0..self.session_info.validator_groups.len())
|
||||
.map(|i| (ParaId::from(i as u32), PerParaData::new(1, vec![1, 2, 3].into())))
|
||||
.collect(),
|
||||
minimum_backing_votes: 2,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_dummy_leaf_with_disabled_validators(
|
||||
&self,
|
||||
relay_parent: Hash,
|
||||
disabled_validators: Vec<ValidatorIndex>,
|
||||
) -> TestLeaf {
|
||||
TestLeaf { disabled_validators, ..self.make_dummy_leaf(relay_parent) }
|
||||
}
|
||||
|
||||
fn make_dummy_leaf_with_min_backing_votes(
|
||||
&self,
|
||||
relay_parent: Hash,
|
||||
minimum_backing_votes: u32,
|
||||
) -> TestLeaf {
|
||||
TestLeaf { minimum_backing_votes, ..self.make_dummy_leaf(relay_parent) }
|
||||
}
|
||||
|
||||
fn make_availability_cores(&self, f: impl Fn(usize) -> CoreState) -> Vec<CoreState> {
|
||||
(0..self.session_info.validator_groups.len()).map(f).collect()
|
||||
}
|
||||
@@ -240,6 +258,19 @@ impl TestState {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn index_within_group(
|
||||
&self,
|
||||
group_index: GroupIndex,
|
||||
validator_index: ValidatorIndex,
|
||||
) -> Option<usize> {
|
||||
self.session_info
|
||||
.validator_groups
|
||||
.get(group_index)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.position(|&i| i == validator_index)
|
||||
}
|
||||
|
||||
fn discovery_id(&self, validator_index: ValidatorIndex) -> AuthorityDiscoveryId {
|
||||
self.session_info.discovery_keys[validator_index.0 as usize].clone()
|
||||
}
|
||||
@@ -284,7 +315,7 @@ impl TestState {
|
||||
&mut self,
|
||||
peer: PeerId,
|
||||
request: AttestedCandidateRequest,
|
||||
) -> impl Future<Output = sc_network::config::OutgoingResponse> {
|
||||
) -> impl Future<Output = Option<sc_network::config::OutgoingResponse>> {
|
||||
let (tx, rx) = futures::channel::oneshot::channel();
|
||||
let req = sc_network::config::IncomingRequest {
|
||||
peer,
|
||||
@@ -293,7 +324,7 @@ impl TestState {
|
||||
};
|
||||
self.req_sender.send(req).await.unwrap();
|
||||
|
||||
rx.map(|r| r.unwrap())
|
||||
rx.map(|r| r.ok())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +397,9 @@ struct TestLeaf {
|
||||
parent_hash: Hash,
|
||||
session: SessionIndex,
|
||||
availability_cores: Vec<CoreState>,
|
||||
disabled_validators: Vec<ValidatorIndex>,
|
||||
para_data: Vec<(ParaId, PerParaData)>,
|
||||
minimum_backing_votes: u32,
|
||||
}
|
||||
|
||||
impl TestLeaf {
|
||||
@@ -447,9 +480,7 @@ async fn setup_test_and_connect_peers(
|
||||
}
|
||||
}
|
||||
|
||||
activate_leaf(overseer, &test_leaf, &state, true).await;
|
||||
|
||||
answer_expected_hypothetical_depth_request(overseer, vec![], Some(relay_parent), false).await;
|
||||
activate_leaf(overseer, &test_leaf, &state, true, vec![]).await;
|
||||
|
||||
// Send gossip topology.
|
||||
send_new_topology(overseer, state.make_dummy_topology()).await;
|
||||
@@ -472,6 +503,7 @@ async fn activate_leaf(
|
||||
leaf: &TestLeaf,
|
||||
test_state: &TestState,
|
||||
is_new_session: bool,
|
||||
hypothetical_frontier: Vec<(HypotheticalCandidate, FragmentTreeMembership)>,
|
||||
) {
|
||||
let activated = new_leaf(leaf.hash, leaf.number);
|
||||
|
||||
@@ -481,7 +513,14 @@ async fn activate_leaf(
|
||||
))))
|
||||
.await;
|
||||
|
||||
handle_leaf_activation(virtual_overseer, leaf, test_state, is_new_session).await;
|
||||
handle_leaf_activation(
|
||||
virtual_overseer,
|
||||
leaf,
|
||||
test_state,
|
||||
is_new_session,
|
||||
hypothetical_frontier,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn handle_leaf_activation(
|
||||
@@ -489,8 +528,18 @@ async fn handle_leaf_activation(
|
||||
leaf: &TestLeaf,
|
||||
test_state: &TestState,
|
||||
is_new_session: bool,
|
||||
hypothetical_frontier: Vec<(HypotheticalCandidate, FragmentTreeMembership)>,
|
||||
) {
|
||||
let TestLeaf { number, hash, parent_hash, para_data, session, availability_cores } = leaf;
|
||||
let TestLeaf {
|
||||
number,
|
||||
hash,
|
||||
parent_hash,
|
||||
para_data,
|
||||
session,
|
||||
availability_cores,
|
||||
disabled_validators,
|
||||
minimum_backing_votes,
|
||||
} = leaf;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
@@ -530,51 +579,82 @@ async fn handle_leaf_activation(
|
||||
}
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::RuntimeApi(
|
||||
RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionIndexForChild(tx))) if parent == *hash => {
|
||||
tx.send(Ok(*session)).unwrap();
|
||||
}
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::RuntimeApi(
|
||||
RuntimeApiMessage::Request(parent, RuntimeApiRequest::AvailabilityCores(tx))) if parent == *hash => {
|
||||
tx.send(Ok(availability_cores.clone())).unwrap();
|
||||
}
|
||||
);
|
||||
|
||||
let validator_groups = test_state.session_info.validator_groups.to_vec();
|
||||
let group_rotation_info =
|
||||
GroupRotationInfo { session_start_block: 1, group_rotation_frequency: 12, now: 1 };
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::RuntimeApi(
|
||||
RuntimeApiMessage::Request(parent, RuntimeApiRequest::ValidatorGroups(tx))) if parent == *hash => {
|
||||
tx.send(Ok((validator_groups, group_rotation_info))).unwrap();
|
||||
}
|
||||
);
|
||||
|
||||
if is_new_session {
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::RuntimeApi(
|
||||
RuntimeApiMessage::Request(parent, RuntimeApiRequest::SessionInfo(s, tx))) if parent == *hash && s == *session => {
|
||||
loop {
|
||||
match virtual_overseer.recv().await {
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
_parent,
|
||||
RuntimeApiRequest::Version(tx),
|
||||
)) => {
|
||||
tx.send(Ok(RuntimeApiRequest::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT)).unwrap();
|
||||
},
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
parent,
|
||||
RuntimeApiRequest::DisabledValidators(tx),
|
||||
)) if parent == *hash => {
|
||||
tx.send(Ok(disabled_validators.clone())).unwrap();
|
||||
},
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
_parent,
|
||||
RuntimeApiRequest::DisabledValidators(tx),
|
||||
)) => {
|
||||
tx.send(Ok(Vec::new())).unwrap();
|
||||
},
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
_parent, // assume all active leaves are in the same session
|
||||
RuntimeApiRequest::SessionIndexForChild(tx),
|
||||
)) => {
|
||||
tx.send(Ok(*session)).unwrap();
|
||||
},
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
parent,
|
||||
RuntimeApiRequest::SessionInfo(s, tx),
|
||||
)) if parent == *hash && s == *session => {
|
||||
assert!(is_new_session, "only expecting this call in a new session");
|
||||
tx.send(Ok(Some(test_state.session_info.clone()))).unwrap();
|
||||
}
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
},
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
parent,
|
||||
RuntimeApiRequest::MinimumBackingVotes(session_index, tx),
|
||||
)) if parent == *hash && session_index == *session => {
|
||||
tx.send(Ok(2)).unwrap();
|
||||
}
|
||||
);
|
||||
assert!(is_new_session, "only expecting this call in a new session");
|
||||
tx.send(Ok(*minimum_backing_votes)).unwrap();
|
||||
},
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
parent,
|
||||
RuntimeApiRequest::AvailabilityCores(tx),
|
||||
)) if parent == *hash => {
|
||||
tx.send(Ok(availability_cores.clone())).unwrap();
|
||||
},
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
parent,
|
||||
RuntimeApiRequest::ValidatorGroups(tx),
|
||||
)) if parent == *hash => {
|
||||
let validator_groups = test_state.session_info.validator_groups.to_vec();
|
||||
let group_rotation_info = GroupRotationInfo {
|
||||
session_start_block: 1,
|
||||
group_rotation_frequency: 12,
|
||||
now: 1,
|
||||
};
|
||||
tx.send(Ok((validator_groups, group_rotation_info))).unwrap();
|
||||
},
|
||||
AllMessages::ProspectiveParachains(
|
||||
ProspectiveParachainsMessage::GetHypotheticalFrontier(req, tx),
|
||||
) => {
|
||||
assert_eq!(req.fragment_tree_relay_parent, Some(*hash));
|
||||
assert!(!req.backed_in_path_only);
|
||||
for (i, (candidate, _)) in hypothetical_frontier.iter().enumerate() {
|
||||
assert!(
|
||||
req.candidates.iter().any(|c| &c == &candidate),
|
||||
"did not receive request for hypothetical candidate {}",
|
||||
i,
|
||||
);
|
||||
}
|
||||
tx.send(hypothetical_frontier).unwrap();
|
||||
// this is the last expected runtime api call
|
||||
break
|
||||
},
|
||||
msg => panic!("unexpected runtime API call: {msg:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,16 +694,14 @@ async fn handle_sent_request(
|
||||
async fn answer_expected_hypothetical_depth_request(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
responses: Vec<(HypotheticalCandidate, FragmentTreeMembership)>,
|
||||
expected_leaf_hash: Option<Hash>,
|
||||
expected_backed_in_path_only: bool,
|
||||
) {
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::ProspectiveParachains(
|
||||
ProspectiveParachainsMessage::GetHypotheticalFrontier(req, tx)
|
||||
) => {
|
||||
assert_eq!(req.fragment_tree_relay_parent, expected_leaf_hash);
|
||||
assert_eq!(req.backed_in_path_only, expected_backed_in_path_only);
|
||||
assert_eq!(req.fragment_tree_relay_parent, None);
|
||||
assert!(!req.backed_in_path_only);
|
||||
for (i, (candidate, _)) in responses.iter().enumerate() {
|
||||
assert!(
|
||||
req.candidates.iter().any(|c| &c == &candidate),
|
||||
|
||||
Reference in New Issue
Block a user