mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-16 20:11:03 +00:00
Approval-distribution: Fix out-of-view messages caused by a race condition in view updates (#5089)
* Try to fix out-of-view messages in approval distribution Suggested by: @ordian * Cargo fmt * Add a unit test for the proposed fix * Spelling fix * Use a simplier approach to fix the race condition as suggested by @rphmeier * Cargo fmt run
This commit is contained in:
@@ -294,6 +294,20 @@ impl State {
|
|||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
for (peer_id, view) in self.peer_views.iter() {
|
||||||
|
let intersection = view.iter().filter(|h| new_hashes.contains(h));
|
||||||
|
let view_intersection = View::new(intersection.cloned(), view.finalized_number);
|
||||||
|
Self::unify_with_peer(
|
||||||
|
ctx,
|
||||||
|
&self.gossip_peers,
|
||||||
|
metrics,
|
||||||
|
&mut self.blocks,
|
||||||
|
peer_id.clone(),
|
||||||
|
view_intersection,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
let pending_now_known = self
|
let pending_now_known = self
|
||||||
.pending_known
|
.pending_known
|
||||||
.keys()
|
.keys()
|
||||||
@@ -348,20 +362,6 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (peer_id, view) in self.peer_views.iter() {
|
|
||||||
let intersection = view.iter().filter(|h| new_hashes.contains(h));
|
|
||||||
let view_intersection = View::new(intersection.cloned(), view.finalized_number);
|
|
||||||
Self::unify_with_peer(
|
|
||||||
ctx,
|
|
||||||
&self.gossip_peers,
|
|
||||||
metrics,
|
|
||||||
&mut self.blocks,
|
|
||||||
peer_id.clone(),
|
|
||||||
view_intersection,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_incoming_peer_message(
|
async fn process_incoming_peer_message(
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use futures::{executor, future, Future};
|
use futures::{executor, future, Future};
|
||||||
use polkadot_node_network_protocol::{view, ObservedRole};
|
use polkadot_node_network_protocol::{our_view, view, ObservedRole};
|
||||||
use polkadot_node_primitives::approval::{
|
use polkadot_node_primitives::approval::{
|
||||||
AssignmentCertKind, VRFOutput, VRFProof, RELAY_VRF_MODULO_CONTEXT,
|
AssignmentCertKind, VRFOutput, VRFProof, RELAY_VRF_MODULO_CONTEXT,
|
||||||
};
|
};
|
||||||
@@ -974,3 +974,81 @@ fn sends_assignments_even_when_state_is_approved() {
|
|||||||
virtual_overseer
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://github.com/paritytech/polkadot/pull/5089>
|
||||||
|
///
|
||||||
|
/// 1. Receive remote peer view update with an unknown head
|
||||||
|
/// 2. Receive assignments for that unknown head
|
||||||
|
/// 3. Update our view and import the new block
|
||||||
|
/// 4. Expect that no reputation with `COST_UNEXPECTED_MESSAGE` is applied
|
||||||
|
#[test]
|
||||||
|
fn race_condition_in_local_vs_remote_view_update() {
|
||||||
|
let parent_hash = Hash::repeat_byte(0xFF);
|
||||||
|
let peer_a = PeerId::random();
|
||||||
|
let hash_b = Hash::repeat_byte(0xBB);
|
||||||
|
|
||||||
|
let _ = test_harness(State::default(), |mut virtual_overseer| async move {
|
||||||
|
let overseer = &mut virtual_overseer;
|
||||||
|
let peer = &peer_a;
|
||||||
|
|
||||||
|
// Test a small number of candidates
|
||||||
|
let candidates_count = 1;
|
||||||
|
let meta = BlockApprovalMeta {
|
||||||
|
hash: hash_b.clone(),
|
||||||
|
parent_hash,
|
||||||
|
number: 2,
|
||||||
|
candidates: vec![Default::default(); candidates_count],
|
||||||
|
slot: 1.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// This will send a peer view that is ahead of our view
|
||||||
|
setup_peer_with_view(overseer, peer, view![hash_b]).await;
|
||||||
|
|
||||||
|
// Send our view update to include a new head
|
||||||
|
overseer_send(
|
||||||
|
overseer,
|
||||||
|
ApprovalDistributionMessage::NetworkBridgeUpdateV1(NetworkBridgeEvent::OurViewChange(
|
||||||
|
our_view![hash_b],
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// send assignments related to `hash_b` but they will come to the MessagesPending
|
||||||
|
let assignments: Vec<_> = (0..candidates_count)
|
||||||
|
.map(|candidate_index| {
|
||||||
|
let validator_index = ValidatorIndex(candidate_index as u32);
|
||||||
|
let cert = fake_assignment_cert(hash_b, validator_index);
|
||||||
|
(cert, candidate_index as u32)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone());
|
||||||
|
send_message_from_peer(overseer, peer, msg.clone()).await;
|
||||||
|
|
||||||
|
// This will handle pending messages being processed
|
||||||
|
let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]);
|
||||||
|
overseer_send(overseer, msg).await;
|
||||||
|
|
||||||
|
for i in 0..candidates_count {
|
||||||
|
// Previously, this has caused out-of-view assignments/approvals
|
||||||
|
//expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await;
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
overseer_recv(overseer).await,
|
||||||
|
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||||
|
assignment,
|
||||||
|
claimed_candidate_index,
|
||||||
|
tx,
|
||||||
|
)) => {
|
||||||
|
assert_eq!(assignment, assignments[i].0);
|
||||||
|
assert_eq!(claimed_candidate_index, assignments[i].1);
|
||||||
|
tx.send(AssignmentCheckResult::Accepted).unwrap();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Since we have a valid statement pending, this should always occur
|
||||||
|
expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await;
|
||||||
|
}
|
||||||
|
virtual_overseer
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user