mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-30 18:57:57 +00:00
statement-distribution: Add tests for incoming acknowledgements (#2498)
This commit is contained in:
@@ -44,6 +44,8 @@ fn backed_candidate_leads_to_advertisement() {
|
||||
let local_group_index = local_validator.group_index.unwrap();
|
||||
let local_para = ParaId::from(local_group_index.0);
|
||||
|
||||
let other_group = next_group_index(local_group_index, validator_count, group_size);
|
||||
|
||||
let test_leaf = state.make_dummy_leaf(relay_parent);
|
||||
|
||||
let (candidate, pvd) = make_candidate(
|
||||
@@ -56,13 +58,12 @@ fn backed_candidate_leads_to_advertisement() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let other_group_validators = state.group_validators(local_group_index, true);
|
||||
let target_group_validators =
|
||||
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];
|
||||
let v_d = target_group_validators[1];
|
||||
let local_group_validators = state.group_validators(local_group_index, true);
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_a = local_group_validators[0];
|
||||
let v_b = local_group_validators[1];
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
|
||||
// peer A is in group, has relay parent in view.
|
||||
// peer B is in group, has no relay parent in view.
|
||||
@@ -274,12 +275,12 @@ fn received_advertisement_before_confirmation_leads_to_request() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
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];
|
||||
let local_group_validators = state.group_validators(local_group_index, true);
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_a = local_group_validators[0];
|
||||
let v_b = local_group_validators[1];
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
|
||||
// peer A is in group, has relay parent in view.
|
||||
// peer B is in group, has no relay parent in view.
|
||||
@@ -429,19 +430,33 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() {
|
||||
async_backing_params: None,
|
||||
};
|
||||
|
||||
let relay_parent = Hash::repeat_byte(1);
|
||||
let peer_c = PeerId::random();
|
||||
let peer_d = PeerId::random();
|
||||
let peer_e = PeerId::random();
|
||||
|
||||
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 peers_to_connect = [
|
||||
TestPeerToConnect { local: true, relay_parent_in_view: false },
|
||||
TestPeerToConnect { local: true, relay_parent_in_view: false },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: true },
|
||||
];
|
||||
|
||||
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);
|
||||
let TestSetupInfo {
|
||||
other_group,
|
||||
other_para,
|
||||
relay_parent,
|
||||
test_leaf,
|
||||
peers,
|
||||
validators,
|
||||
..
|
||||
} = setup_test_and_connect_peers(
|
||||
&state,
|
||||
&mut overseer,
|
||||
validator_count,
|
||||
group_size,
|
||||
&peers_to_connect,
|
||||
)
|
||||
.await;
|
||||
let [_, _, peer_c, peer_d, _] = peers[..] else { panic!() };
|
||||
let [_, _, v_c, v_d, v_e] = validators[..] else { panic!() };
|
||||
|
||||
let (candidate, pvd) = make_candidate(
|
||||
relay_parent,
|
||||
@@ -453,52 +468,6 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let target_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = target_group_validators[0];
|
||||
let v_d = target_group_validators[1];
|
||||
let v_e = target_group_validators[2];
|
||||
|
||||
// Connect C, D, E
|
||||
{
|
||||
connect_peer(
|
||||
&mut overseer,
|
||||
peer_c.clone(),
|
||||
Some(vec![state.discovery_id(v_c)].into_iter().collect()),
|
||||
)
|
||||
.await;
|
||||
|
||||
connect_peer(
|
||||
&mut overseer,
|
||||
peer_d.clone(),
|
||||
Some(vec![state.discovery_id(v_d)].into_iter().collect()),
|
||||
)
|
||||
.await;
|
||||
|
||||
connect_peer(
|
||||
&mut overseer,
|
||||
peer_e.clone(),
|
||||
Some(vec![state.discovery_id(v_e)].into_iter().collect()),
|
||||
)
|
||||
.await;
|
||||
|
||||
send_peer_view_change(&mut overseer, peer_c.clone(), view![relay_parent]).await;
|
||||
send_peer_view_change(&mut overseer, peer_d.clone(), view![relay_parent]).await;
|
||||
send_peer_view_change(&mut overseer, peer_e.clone(), view![relay_parent]).await;
|
||||
}
|
||||
|
||||
activate_leaf(&mut overseer, &test_leaf, &state, true).await;
|
||||
|
||||
answer_expected_hypothetical_depth_request(
|
||||
&mut overseer,
|
||||
vec![],
|
||||
Some(relay_parent),
|
||||
false,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Send gossip topology.
|
||||
send_new_topology(&mut overseer, state.make_dummy_topology()).await;
|
||||
|
||||
let manifest = BackedCandidateManifest {
|
||||
relay_parent,
|
||||
candidate_hash,
|
||||
@@ -530,14 +499,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() {
|
||||
|
||||
// Receive an advertisement from C.
|
||||
{
|
||||
send_peer_message(
|
||||
&mut overseer,
|
||||
peer_c.clone(),
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateManifest(
|
||||
manifest.clone(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
send_manifest_from_peer(&mut overseer, peer_c, manifest.clone()).await;
|
||||
|
||||
// Should send a request to C.
|
||||
let statements = vec![
|
||||
@@ -563,37 +525,16 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() {
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_matches!(
|
||||
overseer.recv().await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r)))
|
||||
if p == peer_c && r == BENEFIT_VALID_STATEMENT.into()
|
||||
);
|
||||
assert_matches!(
|
||||
overseer.recv().await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r)))
|
||||
if p == peer_c && r == BENEFIT_VALID_STATEMENT.into()
|
||||
);
|
||||
assert_matches!(
|
||||
overseer.recv().await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r)))
|
||||
if p == peer_c && r == BENEFIT_VALID_STATEMENT.into()
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
overseer.recv().await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r)))
|
||||
if p == peer_c && r == BENEFIT_VALID_RESPONSE.into()
|
||||
);
|
||||
assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_STATEMENT);
|
||||
assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_STATEMENT);
|
||||
assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_STATEMENT);
|
||||
assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_RESPONSE);
|
||||
|
||||
answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await;
|
||||
}
|
||||
|
||||
// Receive Backed message.
|
||||
overseer
|
||||
.send(FromOrchestra::Communication {
|
||||
msg: StatementDistributionMessage::Backed(candidate_hash),
|
||||
})
|
||||
.await;
|
||||
send_backed_message(&mut overseer, candidate_hash).await;
|
||||
|
||||
// Should send an acknowledgement back to C.
|
||||
{
|
||||
@@ -625,14 +566,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() {
|
||||
|
||||
// Receive a manifest about the same candidate from peer D.
|
||||
{
|
||||
send_peer_message(
|
||||
&mut overseer,
|
||||
peer_d.clone(),
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateManifest(
|
||||
manifest.clone(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
send_manifest_from_peer(&mut overseer, peer_d, manifest.clone()).await;
|
||||
|
||||
let expected_ack = BackedCandidateAcknowledgement {
|
||||
candidate_hash,
|
||||
@@ -665,6 +599,360 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn receive_ack_for_unconfirmed_candidate() {
|
||||
let validator_count = 6;
|
||||
let group_size = 3;
|
||||
let config = TestConfig {
|
||||
validator_count,
|
||||
group_size,
|
||||
local_validator: LocalRole::Validator,
|
||||
async_backing_params: None,
|
||||
};
|
||||
|
||||
test_harness(config, |state, mut overseer| async move {
|
||||
let peers_to_connect = [
|
||||
TestPeerToConnect { local: true, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: true, relay_parent_in_view: false },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: false },
|
||||
];
|
||||
let TestSetupInfo { local_para, relay_parent, test_leaf, peers, .. } =
|
||||
setup_test_and_connect_peers(
|
||||
&state,
|
||||
&mut overseer,
|
||||
validator_count,
|
||||
group_size,
|
||||
&peers_to_connect,
|
||||
)
|
||||
.await;
|
||||
let [_, _, peer_c, _] = peers[..] else { panic!() };
|
||||
|
||||
let (candidate, _pvd) = make_candidate(
|
||||
relay_parent,
|
||||
1,
|
||||
local_para,
|
||||
test_leaf.para_data(local_para).head_data.clone(),
|
||||
vec![4, 5, 6].into(),
|
||||
Hash::repeat_byte(42).into(),
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let ack = BackedCandidateAcknowledgement {
|
||||
candidate_hash,
|
||||
statement_knowledge: StatementFilter {
|
||||
seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1],
|
||||
validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0],
|
||||
},
|
||||
};
|
||||
|
||||
// Receive an acknowledgement from a peer before the candidate is confirmed.
|
||||
send_ack_from_peer(&mut overseer, peer_c, ack.clone()).await;
|
||||
assert_peer_reported!(
|
||||
&mut overseer,
|
||||
peer_c,
|
||||
COST_UNEXPECTED_ACKNOWLEDGEMENT_UNKNOWN_CANDIDATE,
|
||||
);
|
||||
|
||||
overseer
|
||||
});
|
||||
}
|
||||
|
||||
// Test receiving unexpected and expected acknowledgements for a locally confirmed candidate.
|
||||
#[test]
|
||||
fn received_acknowledgements_for_locally_confirmed() {
|
||||
let validator_count = 6;
|
||||
let group_size = 3;
|
||||
let config = TestConfig {
|
||||
validator_count,
|
||||
group_size,
|
||||
local_validator: LocalRole::Validator,
|
||||
async_backing_params: None,
|
||||
};
|
||||
|
||||
test_harness(config, |state, mut overseer| async move {
|
||||
let peers_to_connect = [
|
||||
TestPeerToConnect { local: true, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: true, relay_parent_in_view: false },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: false },
|
||||
];
|
||||
let TestSetupInfo {
|
||||
local_validator,
|
||||
local_group,
|
||||
local_para,
|
||||
relay_parent,
|
||||
test_leaf,
|
||||
peers,
|
||||
validators,
|
||||
..
|
||||
} = setup_test_and_connect_peers(
|
||||
&state,
|
||||
&mut overseer,
|
||||
validator_count,
|
||||
group_size,
|
||||
&peers_to_connect,
|
||||
)
|
||||
.await;
|
||||
let [peer_a, peer_b, peer_c, peer_d] = peers[..] else { panic!() };
|
||||
let [_, v_b, _, _] = validators[..] else { panic!() };
|
||||
|
||||
let (candidate, pvd) = make_candidate(
|
||||
relay_parent,
|
||||
1,
|
||||
local_para,
|
||||
test_leaf.para_data(local_para).head_data.clone(),
|
||||
vec![4, 5, 6].into(),
|
||||
Hash::repeat_byte(42).into(),
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let ack = BackedCandidateAcknowledgement {
|
||||
candidate_hash,
|
||||
statement_knowledge: StatementFilter {
|
||||
seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1],
|
||||
validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0],
|
||||
},
|
||||
};
|
||||
|
||||
// Confirm the candidate locally so that we don't send out requests.
|
||||
{
|
||||
let statement = state
|
||||
.sign_full_statement(
|
||||
local_validator.validator_index,
|
||||
Statement::Seconded(candidate.clone()),
|
||||
&SigningContext { parent_hash: relay_parent, session_index: 1 },
|
||||
pvd.clone(),
|
||||
)
|
||||
.clone();
|
||||
|
||||
send_share_message(&mut overseer, relay_parent, statement).await;
|
||||
|
||||
assert_matches!(
|
||||
overseer.recv().await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a]
|
||||
);
|
||||
|
||||
answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await;
|
||||
}
|
||||
|
||||
// Receive an unexpected acknowledgement from peer D.
|
||||
send_ack_from_peer(&mut overseer, peer_d, ack.clone()).await;
|
||||
assert_peer_reported!(&mut overseer, peer_d, COST_UNEXPECTED_MANIFEST_DISALLOWED);
|
||||
|
||||
// Send statement from peer B.
|
||||
{
|
||||
let statement = state
|
||||
.sign_statement(
|
||||
v_b,
|
||||
CompactStatement::Seconded(candidate_hash),
|
||||
&SigningContext { parent_hash: relay_parent, session_index: 1 },
|
||||
)
|
||||
.as_unchecked()
|
||||
.clone();
|
||||
|
||||
send_peer_message(
|
||||
&mut overseer,
|
||||
peer_b.clone(),
|
||||
protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_peer_reported!(&mut overseer, peer_b, BENEFIT_VALID_STATEMENT_FIRST);
|
||||
|
||||
assert_matches!(
|
||||
overseer.recv().await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a]
|
||||
);
|
||||
}
|
||||
|
||||
// Send Backed notification.
|
||||
{
|
||||
send_backed_message(&mut overseer, candidate_hash).await;
|
||||
|
||||
// We should send out a manifest.
|
||||
assert_matches!(
|
||||
overseer.recv().await,
|
||||
AllMessages:: NetworkBridgeTx(
|
||||
NetworkBridgeTxMessage::SendValidationMessage(
|
||||
peers,
|
||||
Versioned::V2(
|
||||
protocol_v2::ValidationProtocol::StatementDistribution(
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest),
|
||||
),
|
||||
),
|
||||
)
|
||||
) => {
|
||||
assert_eq!(peers, vec![peer_c]);
|
||||
assert_eq!(manifest, BackedCandidateManifest {
|
||||
relay_parent,
|
||||
candidate_hash,
|
||||
group_index: local_group,
|
||||
para_id: local_para,
|
||||
parent_head_data_hash: pvd.parent_head.hash(),
|
||||
statement_knowledge: StatementFilter {
|
||||
seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1],
|
||||
validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0],
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await;
|
||||
}
|
||||
|
||||
// Receive an unexpected acknowledgement from peer D.
|
||||
//
|
||||
// It still shouldn't know this manifest.
|
||||
send_ack_from_peer(&mut overseer, peer_d, ack.clone()).await;
|
||||
assert_peer_reported!(&mut overseer, peer_d, COST_UNEXPECTED_MANIFEST_DISALLOWED);
|
||||
|
||||
// Receive an acknowledgement from peer C.
|
||||
//
|
||||
// It's OK, we know they know it because we sent them a manifest.
|
||||
send_ack_from_peer(&mut overseer, peer_c, ack.clone()).await;
|
||||
|
||||
// What happens if we get another valid ack?
|
||||
send_ack_from_peer(&mut overseer, peer_c, ack.clone()).await;
|
||||
|
||||
overseer
|
||||
});
|
||||
}
|
||||
|
||||
// Test receiving unexpected acknowledgements for a candidate confirmed in a different group.
|
||||
#[test]
|
||||
fn received_acknowledgements_for_externally_confirmed() {
|
||||
let validator_count = 6;
|
||||
let group_size = 3;
|
||||
let config = TestConfig {
|
||||
validator_count,
|
||||
group_size,
|
||||
local_validator: LocalRole::Validator,
|
||||
async_backing_params: None,
|
||||
};
|
||||
|
||||
test_harness(config, |state, mut overseer| async move {
|
||||
let peers_to_connect = [
|
||||
TestPeerToConnect { local: true, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: true, relay_parent_in_view: false },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: true },
|
||||
TestPeerToConnect { local: false, relay_parent_in_view: true },
|
||||
];
|
||||
let TestSetupInfo {
|
||||
other_group,
|
||||
other_para,
|
||||
relay_parent,
|
||||
test_leaf,
|
||||
peers,
|
||||
validators,
|
||||
..
|
||||
} = setup_test_and_connect_peers(
|
||||
&state,
|
||||
&mut overseer,
|
||||
validator_count,
|
||||
group_size,
|
||||
&peers_to_connect,
|
||||
)
|
||||
.await;
|
||||
let [peer_a, _, peer_c, peer_d, _] = peers[..] else { panic!() };
|
||||
let [_, _, v_c, v_d, v_e] = validators[..] else { panic!() };
|
||||
|
||||
let (candidate, pvd) = make_candidate(
|
||||
relay_parent,
|
||||
1,
|
||||
other_para,
|
||||
test_leaf.para_data(other_para).head_data.clone(),
|
||||
vec![4, 5, 6].into(),
|
||||
Hash::repeat_byte(42).into(),
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let manifest = BackedCandidateManifest {
|
||||
relay_parent,
|
||||
candidate_hash,
|
||||
group_index: other_group,
|
||||
para_id: other_para,
|
||||
parent_head_data_hash: pvd.parent_head.hash(),
|
||||
statement_knowledge: StatementFilter {
|
||||
seconded_in_group: bitvec::bitvec![u8, Lsb0; 0, 1, 1],
|
||||
validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0],
|
||||
},
|
||||
};
|
||||
|
||||
let statement_c = state
|
||||
.sign_statement(
|
||||
v_c,
|
||||
CompactStatement::Seconded(candidate_hash),
|
||||
&SigningContext { parent_hash: relay_parent, session_index: 1 },
|
||||
)
|
||||
.as_unchecked()
|
||||
.clone();
|
||||
let statement_d = state
|
||||
.sign_statement(
|
||||
v_d,
|
||||
CompactStatement::Seconded(candidate_hash),
|
||||
&SigningContext { parent_hash: relay_parent, session_index: 1 },
|
||||
)
|
||||
.as_unchecked()
|
||||
.clone();
|
||||
|
||||
// Receive an advertisement from C, confirming the candidate.
|
||||
{
|
||||
send_manifest_from_peer(&mut overseer, peer_c, manifest.clone()).await;
|
||||
|
||||
// Should send a request to C.
|
||||
let statements = vec![
|
||||
statement_c.clone(),
|
||||
statement_d.clone(),
|
||||
state
|
||||
.sign_statement(
|
||||
v_e,
|
||||
CompactStatement::Seconded(candidate_hash),
|
||||
&SigningContext { parent_hash: relay_parent, session_index: 1 },
|
||||
)
|
||||
.as_unchecked()
|
||||
.clone(),
|
||||
];
|
||||
handle_sent_request(
|
||||
&mut overseer,
|
||||
peer_c,
|
||||
candidate_hash,
|
||||
StatementFilter::blank(group_size),
|
||||
candidate.clone(),
|
||||
pvd.clone(),
|
||||
statements,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_STATEMENT);
|
||||
assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_STATEMENT);
|
||||
assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_STATEMENT);
|
||||
assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_RESPONSE);
|
||||
|
||||
answer_expected_hypothetical_depth_request(&mut overseer, vec![], None, false).await;
|
||||
}
|
||||
|
||||
let ack = BackedCandidateAcknowledgement {
|
||||
candidate_hash,
|
||||
statement_knowledge: StatementFilter {
|
||||
seconded_in_group: bitvec::bitvec![u8, Lsb0; 1, 1, 1],
|
||||
validated_in_group: bitvec::bitvec![u8, Lsb0; 0, 0, 0],
|
||||
},
|
||||
};
|
||||
|
||||
// Receive an unexpected acknowledgement from peer D.
|
||||
send_ack_from_peer(&mut overseer, peer_d, ack.clone()).await;
|
||||
assert_peer_reported!(&mut overseer, peer_d, COST_UNEXPECTED_MANIFEST_PEER_UNKNOWN);
|
||||
|
||||
// Receive an unexpected acknowledgement from peer A.
|
||||
send_ack_from_peer(&mut overseer, peer_a, ack.clone()).await;
|
||||
assert_peer_reported!(&mut overseer, peer_a, COST_UNEXPECTED_MANIFEST_DISALLOWED);
|
||||
|
||||
overseer
|
||||
});
|
||||
}
|
||||
|
||||
// Received advertisement after confirmation but before backing leads to nothing.
|
||||
#[test]
|
||||
fn received_advertisement_after_confirmation_before_backing() {
|
||||
@@ -701,10 +989,10 @@ fn received_advertisement_after_confirmation_before_backing() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let target_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = target_group_validators[0];
|
||||
let v_d = target_group_validators[1];
|
||||
let v_e = target_group_validators[2];
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
let v_e = other_group_validators[2];
|
||||
|
||||
// Connect C, D, E
|
||||
{
|
||||
@@ -887,10 +1175,10 @@ fn additional_statements_are_shared_after_manifest_exchange() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let target_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = target_group_validators[0];
|
||||
let v_d = target_group_validators[1];
|
||||
let v_e = target_group_validators[2];
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
let v_e = other_group_validators[2];
|
||||
|
||||
// Connect C, D, E
|
||||
{
|
||||
@@ -1183,13 +1471,12 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let other_group_validators = state.group_validators(local_group_index, true);
|
||||
let target_group_validators =
|
||||
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];
|
||||
let v_d = target_group_validators[1];
|
||||
let local_group_validators = state.group_validators(local_group_index, true);
|
||||
let other_group_validators = state.group_validators((local_group_index.0 + 1).into(), true);
|
||||
let v_a = local_group_validators[0];
|
||||
let v_b = local_group_validators[1];
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
|
||||
// peer A is in group, has relay parent in view.
|
||||
// peer B is in group, has no relay parent in view.
|
||||
@@ -1406,13 +1693,12 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let other_group_validators = state.group_validators(local_group_index, true);
|
||||
let target_group_validators =
|
||||
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];
|
||||
let v_d = target_group_validators[1];
|
||||
let local_group_validators = state.group_validators(local_group_index, true);
|
||||
let other_group_validators = state.group_validators((local_group_index.0 + 1).into(), true);
|
||||
let v_a = local_group_validators[0];
|
||||
let v_b = local_group_validators[1];
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
|
||||
// peer A is in group, has relay parent in view.
|
||||
// peer B is in group, has no relay parent in view.
|
||||
@@ -1630,10 +1916,10 @@ fn grid_statements_imported_to_backing() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let target_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = target_group_validators[0];
|
||||
let v_d = target_group_validators[1];
|
||||
let v_e = target_group_validators[2];
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
let v_e = other_group_validators[2];
|
||||
|
||||
// Connect C, D, E
|
||||
{
|
||||
@@ -1835,12 +2121,12 @@ fn advertisements_rejected_from_incorrect_peers() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
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];
|
||||
let local_group_validators = state.group_validators(local_group_index, true);
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_a = local_group_validators[0];
|
||||
let v_b = local_group_validators[1];
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
|
||||
// peer A is in group, has relay parent in view.
|
||||
// peer B is in group, has no relay parent in view.
|
||||
@@ -1979,9 +2265,9 @@ fn manifest_rejected_with_unknown_relay_parent() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let target_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = target_group_validators[0];
|
||||
let v_d = target_group_validators[1];
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
|
||||
// peer C is not in group, has relay parent in view.
|
||||
// peer D is not in group, has no relay parent in view.
|
||||
@@ -2081,9 +2367,9 @@ fn manifest_rejected_when_not_a_validator() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let target_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = target_group_validators[0];
|
||||
let v_d = target_group_validators[1];
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
|
||||
// peer C is not in group, has relay parent in view.
|
||||
// peer D is not in group, has no relay parent in view.
|
||||
@@ -2188,9 +2474,9 @@ fn manifest_rejected_when_group_does_not_match_para() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let target_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = target_group_validators[0];
|
||||
let v_d = target_group_validators[1];
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
|
||||
// peer C is not in group, has relay parent in view.
|
||||
// peer D is not in group, has no relay parent in view.
|
||||
@@ -2294,10 +2580,10 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() {
|
||||
);
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let target_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = target_group_validators[0];
|
||||
let v_d = target_group_validators[1];
|
||||
let v_e = target_group_validators[2];
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
let v_c = other_group_validators[0];
|
||||
let v_d = other_group_validators[1];
|
||||
let v_e = other_group_validators[2];
|
||||
|
||||
// Connect C, D, E
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ use crate::*;
|
||||
use polkadot_node_network_protocol::{
|
||||
grid_topology::TopologyPeerInfo,
|
||||
request_response::{outgoing::Recipient, ReqProtocolNames},
|
||||
v2::{BackedCandidateAcknowledgement, BackedCandidateManifest},
|
||||
view, ObservedRole,
|
||||
};
|
||||
use polkadot_node_primitives::Statement;
|
||||
@@ -377,6 +378,95 @@ impl TestLeaf {
|
||||
}
|
||||
}
|
||||
|
||||
struct TestSetupInfo {
|
||||
local_validator: TestLocalValidator,
|
||||
local_group: GroupIndex,
|
||||
local_para: ParaId,
|
||||
other_group: GroupIndex,
|
||||
other_para: ParaId,
|
||||
relay_parent: Hash,
|
||||
test_leaf: TestLeaf,
|
||||
peers: Vec<PeerId>,
|
||||
validators: Vec<ValidatorIndex>,
|
||||
}
|
||||
|
||||
struct TestPeerToConnect {
|
||||
local: bool,
|
||||
relay_parent_in_view: bool,
|
||||
}
|
||||
|
||||
// TODO: Generalize, use in more places.
|
||||
/// Sets up some test info that is common to most tests, and connects the requested peers.
|
||||
async fn setup_test_and_connect_peers(
|
||||
state: &TestState,
|
||||
overseer: &mut VirtualOverseer,
|
||||
validator_count: usize,
|
||||
group_size: usize,
|
||||
peers_to_connect: &[TestPeerToConnect],
|
||||
) -> TestSetupInfo {
|
||||
let local_validator = state.local.clone().unwrap();
|
||||
let local_group = local_validator.group_index.unwrap();
|
||||
let local_para = ParaId::from(local_group.0);
|
||||
|
||||
let other_group = next_group_index(local_group, validator_count, group_size);
|
||||
let other_para = ParaId::from(other_group.0);
|
||||
|
||||
let relay_parent = Hash::repeat_byte(1);
|
||||
let test_leaf = state.make_dummy_leaf(relay_parent);
|
||||
|
||||
// Because we are testing grid mod, the "target" group (the one we communicate with) is usually
|
||||
// other_group, a non-local group.
|
||||
//
|
||||
// TODO: change based on `LocalRole`?
|
||||
let local_group_validators = state.group_validators(local_group, true);
|
||||
let other_group_validators = state.group_validators(other_group, true);
|
||||
|
||||
let mut peers = vec![];
|
||||
let mut validators = vec![];
|
||||
let mut local_group_idx = 0;
|
||||
let mut other_group_idx = 0;
|
||||
for peer_to_connect in peers_to_connect {
|
||||
let peer = PeerId::random();
|
||||
peers.push(peer);
|
||||
|
||||
let v = if peer_to_connect.local {
|
||||
let v = local_group_validators[local_group_idx];
|
||||
local_group_idx += 1;
|
||||
v
|
||||
} else {
|
||||
let v = other_group_validators[other_group_idx];
|
||||
other_group_idx += 1;
|
||||
v
|
||||
};
|
||||
validators.push(v);
|
||||
|
||||
connect_peer(overseer, peer, Some(vec![state.discovery_id(v)].into_iter().collect())).await;
|
||||
|
||||
if peer_to_connect.relay_parent_in_view {
|
||||
send_peer_view_change(overseer, peer.clone(), view![relay_parent]).await;
|
||||
}
|
||||
}
|
||||
|
||||
activate_leaf(overseer, &test_leaf, &state, true).await;
|
||||
|
||||
answer_expected_hypothetical_depth_request(overseer, vec![], Some(relay_parent), false).await;
|
||||
|
||||
// Send gossip topology.
|
||||
send_new_topology(overseer, state.make_dummy_topology()).await;
|
||||
|
||||
TestSetupInfo {
|
||||
local_validator,
|
||||
local_group,
|
||||
local_para,
|
||||
other_group,
|
||||
other_para,
|
||||
test_leaf,
|
||||
relay_parent,
|
||||
peers,
|
||||
validators,
|
||||
}
|
||||
}
|
||||
|
||||
async fn activate_leaf(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
leaf: &TestLeaf,
|
||||
@@ -547,6 +637,66 @@ async fn answer_expected_hypothetical_depth_request(
|
||||
)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! assert_peer_reported {
|
||||
($virtual_overseer:expr, $peer_id:expr, $rep_change:expr $(,)*) => {
|
||||
assert_matches!(
|
||||
$virtual_overseer.recv().await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r)))
|
||||
if p == $peer_id && r == $rep_change.into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_share_message(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
relay_parent: Hash,
|
||||
statement: SignedFullStatementWithPVD,
|
||||
) {
|
||||
virtual_overseer
|
||||
.send(FromOrchestra::Communication {
|
||||
msg: StatementDistributionMessage::Share(relay_parent, statement),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn send_backed_message(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
candidate_hash: CandidateHash,
|
||||
) {
|
||||
virtual_overseer
|
||||
.send(FromOrchestra::Communication {
|
||||
msg: StatementDistributionMessage::Backed(candidate_hash),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn send_manifest_from_peer(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
peer_id: PeerId,
|
||||
manifest: BackedCandidateManifest,
|
||||
) {
|
||||
send_peer_message(
|
||||
virtual_overseer,
|
||||
peer_id,
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn send_ack_from_peer(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
peer_id: PeerId,
|
||||
ack: BackedCandidateAcknowledgement,
|
||||
) {
|
||||
send_peer_message(
|
||||
virtual_overseer,
|
||||
peer_id,
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateKnown(ack),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
fn validator_pubkeys(val_ids: &[ValidatorPair]) -> IndexedVec<ValidatorIndex, ValidatorId> {
|
||||
val_ids.iter().map(|v| v.public().into()).collect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user