mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-20 14:01:02 +00:00
approval-voting improvement: include all tranche0 assignments in one certificate (#1178)
**_PR migrated from https://github.com/paritytech/polkadot/pull/6782_** This PR will upgrade the network protocol to version 3 -> VStaging which will later be renamed to V3. This version introduces a new kind of assignment certificate that will be used for tranche0 assignments. Instead of issuing/importing one tranche0 assignment per candidate, there will be just one certificate per relay chain block per validator. However, we will not be sending out the new assignment certificates, yet. So everything should work exactly as before. Once the majority of the validators have been upgraded to the new protocol version we will enable the new certificates (starting at a specific relay chain block) with a new client update. There are still a few things that need to be done: - [x] Use bitfield instead of Vec<CandidateIndex>: https://github.com/paritytech/polkadot/pull/6802 - [x] Fix existing approval-distribution and approval-voting tests - [x] Fix bitfield-distribution and statement-distribution tests - [x] Fix network bridge tests - [x] Implement todos in the code - [x] Add tests to cover new code - [x] Update metrics - [x] Remove the approval distribution aggression levels: TBD PR - [x] Parachains DB migration - [x] Test network protocol upgrade on Versi - [x] Versi Load test - [x] Add Zombienet test - [x] Documentation updates - [x] Fix for sending DistributeAssignment for each candidate claimed by a v2 assignment (warning: Importing locally an already known assignment) - [x] Fix AcceptedDuplicate - [x] Fix DB migration so that we can still keep old data. - [x] Final Versi burn in --------- Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> Signed-off-by: Alexandru Gheorghe <alexandru.gheorghe@parity.io> Co-authored-by: Alexandru Gheorghe <alexandru.gheorghe@parity.io>
This commit is contained in:
@@ -14,10 +14,12 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" }
|
||||
polkadot-primitives = { path = "../../../primitives" }
|
||||
polkadot-node-jaeger = { path = "../../jaeger" }
|
||||
rand = "0.8"
|
||||
itertools = "0.10.5"
|
||||
|
||||
futures = "0.3.21"
|
||||
futures-timer = "3.0.2"
|
||||
gum = { package = "tracing-gum", path = "../../gum" }
|
||||
bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-authority-discovery = { path = "../../../../substrate/primitives/authority-discovery" }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use polkadot_node_metrics::metrics::{prometheus, Metrics as MetricsTrait};
|
||||
use polkadot_node_primitives::approval::v2::AssignmentCertKindV2;
|
||||
|
||||
/// Approval Distribution metrics.
|
||||
#[derive(Default, Clone)]
|
||||
@@ -22,21 +23,34 @@ pub struct Metrics(Option<MetricsInner>);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MetricsInner {
|
||||
assignments_imported_total: prometheus::Counter<prometheus::U64>,
|
||||
assignments_imported_total: prometheus::CounterVec<prometheus::U64>,
|
||||
approvals_imported_total: prometheus::Counter<prometheus::U64>,
|
||||
unified_with_peer_total: prometheus::Counter<prometheus::U64>,
|
||||
aggression_l1_messages_total: prometheus::Counter<prometheus::U64>,
|
||||
aggression_l2_messages_total: prometheus::Counter<prometheus::U64>,
|
||||
|
||||
time_unify_with_peer: prometheus::Histogram,
|
||||
time_import_pending_now_known: prometheus::Histogram,
|
||||
time_awaiting_approval_voting: prometheus::Histogram,
|
||||
}
|
||||
|
||||
trait AsLabel {
|
||||
fn as_label(&self) -> &str;
|
||||
}
|
||||
|
||||
impl AsLabel for &AssignmentCertKindV2 {
|
||||
fn as_label(&self) -> &str {
|
||||
match self {
|
||||
AssignmentCertKindV2::RelayVRFDelay { .. } => "VRF Delay",
|
||||
AssignmentCertKindV2::RelayVRFModulo { .. } => "VRF Modulo",
|
||||
AssignmentCertKindV2::RelayVRFModuloCompact { .. } => "VRF Modulo Compact",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Metrics {
|
||||
pub(crate) fn on_assignment_imported(&self) {
|
||||
pub(crate) fn on_assignment_imported(&self, kind: &AssignmentCertKindV2) {
|
||||
if let Some(metrics) = &self.0 {
|
||||
metrics.assignments_imported_total.inc();
|
||||
metrics.assignments_imported_total.with_label_values(&[kind.as_label()]).inc();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,9 +103,12 @@ impl MetricsTrait for Metrics {
|
||||
fn try_register(registry: &prometheus::Registry) -> Result<Self, prometheus::PrometheusError> {
|
||||
let metrics = MetricsInner {
|
||||
assignments_imported_total: prometheus::register(
|
||||
prometheus::Counter::new(
|
||||
"polkadot_parachain_assignments_imported_total",
|
||||
"Number of valid assignments imported locally or from other peers.",
|
||||
prometheus::CounterVec::new(
|
||||
prometheus::Opts::new(
|
||||
"polkadot_parachain_assignments_imported_total",
|
||||
"Number of valid assignments imported locally or from other peers.",
|
||||
),
|
||||
&["kind"],
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
@@ -124,10 +141,16 @@ impl MetricsTrait for Metrics {
|
||||
registry,
|
||||
)?,
|
||||
time_unify_with_peer: prometheus::register(
|
||||
prometheus::Histogram::with_opts(prometheus::HistogramOpts::new(
|
||||
"polkadot_parachain_time_unify_with_peer",
|
||||
"Time spent within fn `unify_with_peer`.",
|
||||
).buckets(vec![0.000625, 0.00125,0.0025, 0.005, 0.0075, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,]))?,
|
||||
prometheus::Histogram::with_opts(
|
||||
prometheus::HistogramOpts::new(
|
||||
"polkadot_parachain_time_unify_with_peer",
|
||||
"Time spent within fn `unify_with_peer`.",
|
||||
)
|
||||
.buckets(vec![
|
||||
0.000625, 0.00125, 0.0025, 0.005, 0.0075, 0.01, 0.025, 0.05, 0.1, 0.25,
|
||||
0.5, 1.0, 2.5, 5.0, 10.0,
|
||||
]),
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
time_import_pending_now_known: prometheus::register(
|
||||
|
||||
@@ -24,20 +24,26 @@ use polkadot_node_network_protocol::{
|
||||
view, ObservedRole,
|
||||
};
|
||||
use polkadot_node_primitives::approval::{
|
||||
AssignmentCertKind, VrfOutput, VrfProof, VrfSignature, RELAY_VRF_MODULO_CONTEXT,
|
||||
v1::{
|
||||
AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, VrfOutput, VrfProof,
|
||||
VrfSignature,
|
||||
},
|
||||
v2::{
|
||||
AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, IndirectAssignmentCertV2,
|
||||
RELAY_VRF_MODULO_CONTEXT,
|
||||
},
|
||||
};
|
||||
use polkadot_node_subsystem::messages::{
|
||||
network_bridge_event, AllMessages, ApprovalCheckError, ReportPeerMessage,
|
||||
};
|
||||
use polkadot_node_subsystem_test_helpers as test_helpers;
|
||||
use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt as _};
|
||||
use polkadot_primitives::{AuthorityDiscoveryId, BlakeTwo256, HashT};
|
||||
use polkadot_primitives::{AuthorityDiscoveryId, BlakeTwo256, CoreIndex, HashT};
|
||||
use polkadot_primitives_test_helpers::dummy_signature;
|
||||
use rand::SeedableRng;
|
||||
use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair;
|
||||
use sp_core::crypto::Pair as PairT;
|
||||
use std::time::Duration;
|
||||
|
||||
type VirtualOverseer = test_helpers::TestSubsystemContextHandle<ApprovalDistributionMessage>;
|
||||
|
||||
fn test_harness<T: Future<Output = VirtualOverseer>>(
|
||||
@@ -219,15 +225,15 @@ async fn setup_gossip_topology(
|
||||
async fn setup_peer_with_view(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
peer_id: &PeerId,
|
||||
validation_version: ValidationVersion,
|
||||
view: View,
|
||||
version: ValidationVersion,
|
||||
) {
|
||||
overseer_send(
|
||||
virtual_overseer,
|
||||
ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected(
|
||||
*peer_id,
|
||||
ObservedRole::Full,
|
||||
validation_version.into(),
|
||||
version.into(),
|
||||
None,
|
||||
)),
|
||||
)
|
||||
@@ -244,12 +250,43 @@ async fn setup_peer_with_view(
|
||||
async fn send_message_from_peer(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
peer_id: &PeerId,
|
||||
msg: net_protocol::ApprovalDistributionMessage,
|
||||
msg: protocol_v1::ApprovalDistributionMessage,
|
||||
) {
|
||||
overseer_send(
|
||||
virtual_overseer,
|
||||
ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(
|
||||
*peer_id, msg,
|
||||
*peer_id,
|
||||
Versioned::V1(msg),
|
||||
)),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn send_message_from_peer_v2(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
peer_id: &PeerId,
|
||||
msg: protocol_v2::ApprovalDistributionMessage,
|
||||
) {
|
||||
overseer_send(
|
||||
virtual_overseer,
|
||||
ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(
|
||||
*peer_id,
|
||||
Versioned::V2(msg),
|
||||
)),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn send_message_from_peer_vstaging(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
peer_id: &PeerId,
|
||||
msg: protocol_vstaging::ApprovalDistributionMessage,
|
||||
) {
|
||||
overseer_send(
|
||||
virtual_overseer,
|
||||
ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(
|
||||
*peer_id,
|
||||
Versioned::VStaging(msg),
|
||||
)),
|
||||
)
|
||||
.await;
|
||||
@@ -273,6 +310,28 @@ fn fake_assignment_cert(block_hash: Hash, validator: ValidatorIndex) -> Indirect
|
||||
}
|
||||
}
|
||||
|
||||
fn fake_assignment_cert_v2(
|
||||
block_hash: Hash,
|
||||
validator: ValidatorIndex,
|
||||
core_bitfield: CoreBitfield,
|
||||
) -> IndirectAssignmentCertV2 {
|
||||
let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT);
|
||||
let msg = b"WhenParachains?";
|
||||
let mut prng = rand_core::OsRng;
|
||||
let keypair = schnorrkel::Keypair::generate_with(&mut prng);
|
||||
let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg));
|
||||
let out = inout.to_output();
|
||||
|
||||
IndirectAssignmentCertV2 {
|
||||
block_hash,
|
||||
validator,
|
||||
cert: AssignmentCertV2 {
|
||||
kind: AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield },
|
||||
vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn expect_reputation_change(
|
||||
virtual_overseer: &mut VirtualOverseer,
|
||||
peer_id: &PeerId,
|
||||
@@ -331,9 +390,9 @@ fn try_import_the_same_assignment() {
|
||||
let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
// setup peers
|
||||
setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await;
|
||||
setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, &peer_c, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await;
|
||||
setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await;
|
||||
setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await;
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
@@ -353,7 +412,7 @@ fn try_import_the_same_assignment() {
|
||||
let assignments = vec![(cert.clone(), 0u32)];
|
||||
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone());
|
||||
send_message_from_peer(overseer, &peer_a, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peer_a, msg).await;
|
||||
|
||||
expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await;
|
||||
|
||||
@@ -362,10 +421,11 @@ fn try_import_the_same_assignment() {
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||
assignment,
|
||||
0u32,
|
||||
claimed_indices,
|
||||
tx,
|
||||
)) => {
|
||||
assert_eq!(assignment, cert);
|
||||
assert_eq!(claimed_indices, 0u32.into());
|
||||
assert_eq!(assignment, cert.into());
|
||||
tx.send(AssignmentCheckResult::Accepted).unwrap();
|
||||
}
|
||||
);
|
||||
@@ -385,12 +445,104 @@ fn try_import_the_same_assignment() {
|
||||
}
|
||||
);
|
||||
|
||||
// setup new peer
|
||||
setup_peer_with_view(overseer, &peer_d, ValidationVersion::V1, view![]).await;
|
||||
// setup new peer with V2
|
||||
setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::VStaging).await;
|
||||
|
||||
// send the same assignment from peer_d
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments);
|
||||
send_message_from_peer(overseer, &peer_d, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peer_d, msg).await;
|
||||
|
||||
expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await;
|
||||
expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await;
|
||||
|
||||
assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent");
|
||||
virtual_overseer
|
||||
});
|
||||
}
|
||||
|
||||
/// Just like `try_import_the_same_assignment` but use `VRFModuloCompact` assignments for multiple
|
||||
/// cores.
|
||||
#[test]
|
||||
fn try_import_the_same_assignment_v2() {
|
||||
let peer_a = PeerId::random();
|
||||
let peer_b = PeerId::random();
|
||||
let peer_c = PeerId::random();
|
||||
let peer_d = PeerId::random();
|
||||
let parent_hash = Hash::repeat_byte(0xFF);
|
||||
let hash = Hash::repeat_byte(0xAA);
|
||||
|
||||
let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
// setup peers
|
||||
setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::VStaging).await;
|
||||
setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::VStaging).await;
|
||||
setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::VStaging).await;
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
hash,
|
||||
parent_hash,
|
||||
number: 2,
|
||||
candidates: vec![Default::default(); 1],
|
||||
slot: 1.into(),
|
||||
session: 1,
|
||||
};
|
||||
let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]);
|
||||
overseer_send(overseer, msg).await;
|
||||
|
||||
// send the assignment related to `hash`
|
||||
let validator_index = ValidatorIndex(0);
|
||||
let cores = vec![1, 2, 3, 4];
|
||||
let core_bitfield: CoreBitfield = cores
|
||||
.iter()
|
||||
.map(|index| CoreIndex(*index))
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone());
|
||||
let assignments = vec![(cert.clone(), cores.clone().try_into().unwrap())];
|
||||
|
||||
let msg = protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments.clone());
|
||||
send_message_from_peer_vstaging(overseer, &peer_a, msg).await;
|
||||
|
||||
expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await;
|
||||
|
||||
// send an `Accept` message from the Approval Voting subsystem
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||
assignment,
|
||||
claimed_indices,
|
||||
tx,
|
||||
)) => {
|
||||
assert_eq!(claimed_indices, cores.try_into().unwrap());
|
||||
assert_eq!(assignment, cert.into());
|
||||
tx.send(AssignmentCheckResult::Accepted).unwrap();
|
||||
}
|
||||
);
|
||||
|
||||
expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await;
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
peers,
|
||||
Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution(
|
||||
protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments)
|
||||
))
|
||||
)) => {
|
||||
assert_eq!(peers.len(), 2);
|
||||
assert_eq!(assignments.len(), 1);
|
||||
}
|
||||
);
|
||||
|
||||
// setup new peer
|
||||
setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::VStaging).await;
|
||||
|
||||
// send the same assignment from peer_d
|
||||
let msg = protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments);
|
||||
send_message_from_peer_vstaging(overseer, &peer_d, msg).await;
|
||||
|
||||
expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await;
|
||||
expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await;
|
||||
@@ -413,7 +565,7 @@ fn delay_reputation_change() {
|
||||
let overseer = &mut virtual_overseer;
|
||||
|
||||
// Setup peers
|
||||
setup_peer_with_view(overseer, &peer, ValidationVersion::V1, view![]).await;
|
||||
setup_peer_with_view(overseer, &peer, view![], ValidationVersion::V1).await;
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
@@ -433,17 +585,18 @@ fn delay_reputation_change() {
|
||||
let assignments = vec![(cert.clone(), 0u32)];
|
||||
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone());
|
||||
send_message_from_peer(overseer, &peer, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peer, msg).await;
|
||||
|
||||
// send an `Accept` message from the Approval Voting subsystem
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||
assignment,
|
||||
0u32,
|
||||
claimed_candidates,
|
||||
tx,
|
||||
)) => {
|
||||
assert_eq!(assignment, cert);
|
||||
assert_eq!(assignment.cert, cert.cert.into());
|
||||
assert_eq!(claimed_candidates, vec![0u32].try_into().unwrap());
|
||||
tx.send(AssignmentCheckResult::Accepted).unwrap();
|
||||
}
|
||||
);
|
||||
@@ -474,7 +627,7 @@ fn spam_attack_results_in_negative_reputation_change() {
|
||||
let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
let peer = &peer_a;
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![]).await;
|
||||
setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await;
|
||||
|
||||
// new block `hash_b` with 20 candidates
|
||||
let candidates_count = 20;
|
||||
@@ -501,7 +654,7 @@ fn spam_attack_results_in_negative_reputation_change() {
|
||||
.collect();
|
||||
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone());
|
||||
send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await;
|
||||
send_message_from_peer(overseer, peer, msg.clone()).await;
|
||||
|
||||
for i in 0..candidates_count {
|
||||
expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await;
|
||||
@@ -513,8 +666,8 @@ fn spam_attack_results_in_negative_reputation_change() {
|
||||
claimed_candidate_index,
|
||||
tx,
|
||||
)) => {
|
||||
assert_eq!(assignment, assignments[i].0);
|
||||
assert_eq!(claimed_candidate_index, assignments[i].1);
|
||||
assert_eq!(assignment, assignments[i].0.clone().into());
|
||||
assert_eq!(claimed_candidate_index, assignments[i].1.into());
|
||||
tx.send(AssignmentCheckResult::Accepted).unwrap();
|
||||
}
|
||||
);
|
||||
@@ -533,7 +686,7 @@ fn spam_attack_results_in_negative_reputation_change() {
|
||||
.await;
|
||||
|
||||
// send the assignments again
|
||||
send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await;
|
||||
send_message_from_peer(overseer, peer, msg.clone()).await;
|
||||
|
||||
// each of them will incur `COST_UNEXPECTED_MESSAGE`, not only the first one
|
||||
for _ in 0..candidates_count {
|
||||
@@ -558,7 +711,7 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() {
|
||||
let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
let peer = &peer_a;
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![]).await;
|
||||
setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await;
|
||||
|
||||
// new block `hash` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
@@ -578,7 +731,10 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() {
|
||||
let cert = fake_assignment_cert(hash, validator_index);
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_index.into(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -610,12 +766,12 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() {
|
||||
// the peer could send us it as well
|
||||
let assignments = vec![(cert, candidate_index)];
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments);
|
||||
send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await;
|
||||
send_message_from_peer(overseer, peer, msg.clone()).await;
|
||||
|
||||
assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "we should not punish the peer");
|
||||
|
||||
// send the assignments again
|
||||
send_message_from_peer(overseer, peer, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, peer, msg).await;
|
||||
|
||||
// now we should
|
||||
expect_reputation_change(overseer, peer, COST_DUPLICATE_MESSAGE).await;
|
||||
@@ -633,10 +789,10 @@ fn import_approval_happy_path() {
|
||||
|
||||
let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
// setup peers
|
||||
setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await;
|
||||
setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, &peer_c, ValidationVersion::V1, view![hash]).await;
|
||||
// setup peers with V1 and V2 protocol versions
|
||||
setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await;
|
||||
setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::VStaging).await;
|
||||
setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await;
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
@@ -656,10 +812,14 @@ fn import_approval_happy_path() {
|
||||
let cert = fake_assignment_cert(hash, validator_index);
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert, candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_index.into(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
// 1 peer is v1
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
@@ -668,7 +828,21 @@ fn import_approval_happy_path() {
|
||||
protocol_v1::ApprovalDistributionMessage::Assignments(assignments)
|
||||
))
|
||||
)) => {
|
||||
assert_eq!(peers.len(), 2);
|
||||
assert_eq!(peers.len(), 1);
|
||||
assert_eq!(assignments.len(), 1);
|
||||
}
|
||||
);
|
||||
|
||||
// 1 peer is v2
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
peers,
|
||||
Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution(
|
||||
protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments)
|
||||
))
|
||||
)) => {
|
||||
assert_eq!(peers.len(), 1);
|
||||
assert_eq!(assignments.len(), 1);
|
||||
}
|
||||
);
|
||||
@@ -681,7 +855,7 @@ fn import_approval_happy_path() {
|
||||
signature: dummy_signature(),
|
||||
};
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]);
|
||||
send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peer_b, msg).await;
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
@@ -722,8 +896,8 @@ fn import_approval_bad() {
|
||||
let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
// setup peers
|
||||
setup_peer_with_view(overseer, &peer_a, ValidationVersion::V1, view![]).await;
|
||||
setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await;
|
||||
setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await;
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
@@ -749,14 +923,14 @@ fn import_approval_bad() {
|
||||
signature: dummy_signature(),
|
||||
};
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]);
|
||||
send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peer_b, msg).await;
|
||||
|
||||
expect_reputation_change(overseer, &peer_b, COST_UNEXPECTED_MESSAGE).await;
|
||||
|
||||
// now import an assignment from peer_b
|
||||
let assignments = vec![(cert.clone(), candidate_index)];
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments);
|
||||
send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peer_b, msg).await;
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
@@ -765,8 +939,8 @@ fn import_approval_bad() {
|
||||
i,
|
||||
tx,
|
||||
)) => {
|
||||
assert_eq!(assignment, cert);
|
||||
assert_eq!(i, candidate_index);
|
||||
assert_eq!(assignment, cert.into());
|
||||
assert_eq!(i, candidate_index.into());
|
||||
tx.send(AssignmentCheckResult::Accepted).unwrap();
|
||||
}
|
||||
);
|
||||
@@ -775,7 +949,7 @@ fn import_approval_bad() {
|
||||
|
||||
// and try again
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]);
|
||||
send_message_from_peer(overseer, &peer_b, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peer_b, msg).await;
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
@@ -911,12 +1085,20 @@ fn update_peer_view() {
|
||||
let cert_a = fake_assignment_cert(hash_a, ValidatorIndex(0));
|
||||
let cert_b = fake_assignment_cert(hash_b, ValidatorIndex(0));
|
||||
|
||||
overseer_send(overseer, ApprovalDistributionMessage::DistributeAssignment(cert_a, 0)).await;
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert_a.into(), 0.into()),
|
||||
)
|
||||
.await;
|
||||
|
||||
overseer_send(overseer, ApprovalDistributionMessage::DistributeAssignment(cert_b, 0)).await;
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert_b.into(), 0.into()),
|
||||
)
|
||||
.await;
|
||||
|
||||
// connect a peer
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash_a]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash_a], ValidationVersion::V1).await;
|
||||
|
||||
// we should send relevant assignments to the peer
|
||||
assert_matches!(
|
||||
@@ -934,7 +1116,7 @@ fn update_peer_view() {
|
||||
virtual_overseer
|
||||
});
|
||||
|
||||
assert_eq!(state.peer_data.get(peer).map(|data| data.view.finalized_number), Some(0));
|
||||
assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(0));
|
||||
assert_eq!(
|
||||
state
|
||||
.blocks
|
||||
@@ -965,7 +1147,7 @@ fn update_peer_view() {
|
||||
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert_c.clone(), 0),
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert_c.clone().into(), 0.into()),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -986,7 +1168,7 @@ fn update_peer_view() {
|
||||
virtual_overseer
|
||||
});
|
||||
|
||||
assert_eq!(state.peer_data.get(peer).map(|data| data.view.finalized_number), Some(2));
|
||||
assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(2));
|
||||
assert_eq!(
|
||||
state
|
||||
.blocks
|
||||
@@ -1016,10 +1198,7 @@ fn update_peer_view() {
|
||||
virtual_overseer
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
state.peer_data.get(peer).map(|data| data.view.finalized_number),
|
||||
Some(finalized_number)
|
||||
);
|
||||
assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(finalized_number));
|
||||
assert!(state.blocks.get(&hash_c).unwrap().known_by.get(peer).is_none());
|
||||
}
|
||||
|
||||
@@ -1034,7 +1213,7 @@ fn import_remotely_then_locally() {
|
||||
let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
// setup the peer
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
@@ -1054,7 +1233,7 @@ fn import_remotely_then_locally() {
|
||||
let cert = fake_assignment_cert(hash, validator_index);
|
||||
let assignments = vec![(cert.clone(), candidate_index)];
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone());
|
||||
send_message_from_peer(overseer, peer, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, peer, msg).await;
|
||||
|
||||
// send an `Accept` message from the Approval Voting subsystem
|
||||
assert_matches!(
|
||||
@@ -1064,8 +1243,8 @@ fn import_remotely_then_locally() {
|
||||
i,
|
||||
tx,
|
||||
)) => {
|
||||
assert_eq!(assignment, cert);
|
||||
assert_eq!(i, candidate_index);
|
||||
assert_eq!(assignment, cert.clone().into());
|
||||
assert_eq!(i, candidate_index.into());
|
||||
tx.send(AssignmentCheckResult::Accepted).unwrap();
|
||||
}
|
||||
);
|
||||
@@ -1075,7 +1254,10 @@ fn import_remotely_then_locally() {
|
||||
// import the same assignment locally
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert, candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_index.into(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1089,7 +1271,7 @@ fn import_remotely_then_locally() {
|
||||
signature: dummy_signature(),
|
||||
};
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]);
|
||||
send_message_from_peer(overseer, peer, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, peer, msg).await;
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
@@ -1147,7 +1329,10 @@ fn sends_assignments_even_when_state_is_approved() {
|
||||
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_index.into(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1155,7 +1340,7 @@ fn sends_assignments_even_when_state_is_approved() {
|
||||
.await;
|
||||
|
||||
// connect the peer.
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
|
||||
let assignments = vec![(cert.clone(), candidate_index)];
|
||||
let approvals = vec![approval.clone()];
|
||||
@@ -1191,6 +1376,112 @@ fn sends_assignments_even_when_state_is_approved() {
|
||||
});
|
||||
}
|
||||
|
||||
/// Same as `sends_assignments_even_when_state_is_approved_v2` but with `VRFModuloCompact`
|
||||
/// assignemnts.
|
||||
#[test]
|
||||
fn sends_assignments_even_when_state_is_approved_v2() {
|
||||
let peer_a = PeerId::random();
|
||||
let parent_hash = Hash::repeat_byte(0xFF);
|
||||
let hash = Hash::repeat_byte(0xAA);
|
||||
let peer = &peer_a;
|
||||
|
||||
let _ = test_harness(State::default(), |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
hash,
|
||||
parent_hash,
|
||||
number: 1,
|
||||
candidates: vec![Default::default(); 4],
|
||||
slot: 1.into(),
|
||||
session: 1,
|
||||
};
|
||||
let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]);
|
||||
overseer_send(overseer, msg).await;
|
||||
|
||||
let validator_index = ValidatorIndex(0);
|
||||
let cores = vec![0, 1, 2, 3];
|
||||
let candidate_bitfield: CandidateBitfield = cores.clone().try_into().unwrap();
|
||||
|
||||
let core_bitfield: CoreBitfield = cores
|
||||
.iter()
|
||||
.map(|index| CoreIndex(*index))
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone());
|
||||
|
||||
// Assumes candidate index == core index.
|
||||
let approvals = cores
|
||||
.iter()
|
||||
.map(|core| IndirectSignedApprovalVote {
|
||||
block_hash: hash,
|
||||
candidate_index: *core,
|
||||
validator: validator_index,
|
||||
signature: dummy_signature(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_bitfield.clone(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
for approval in &approvals {
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeApproval(approval.clone()),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
// connect the peer.
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::VStaging).await;
|
||||
|
||||
let assignments = vec![(cert.clone(), candidate_bitfield.clone())];
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
peers,
|
||||
Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution(
|
||||
protocol_vstaging::ApprovalDistributionMessage::Assignments(sent_assignments)
|
||||
))
|
||||
)) => {
|
||||
assert_eq!(peers, vec![*peer]);
|
||||
assert_eq!(sent_assignments, assignments);
|
||||
}
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
peers,
|
||||
Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution(
|
||||
protocol_vstaging::ApprovalDistributionMessage::Approvals(sent_approvals)
|
||||
))
|
||||
)) => {
|
||||
// Construct a hashmaps of approvals for comparison. Approval distribution reorders messages because they are kept in a
|
||||
// hashmap as well.
|
||||
let sent_approvals = sent_approvals.into_iter().map(|approval| (approval.candidate_index, approval)).collect::<HashMap<_,_>>();
|
||||
let approvals = approvals.into_iter().map(|approval| (approval.candidate_index, approval)).collect::<HashMap<_,_>>();
|
||||
|
||||
assert_eq!(peers, vec![*peer]);
|
||||
assert_eq!(sent_approvals, approvals);
|
||||
}
|
||||
);
|
||||
|
||||
assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent");
|
||||
virtual_overseer
|
||||
});
|
||||
}
|
||||
|
||||
/// <https://github.com/paritytech/polkadot/pull/5089>
|
||||
///
|
||||
/// 1. Receive remote peer view update with an unknown head
|
||||
@@ -1219,7 +1510,7 @@ fn race_condition_in_local_vs_remote_view_update() {
|
||||
};
|
||||
|
||||
// This will send a peer view that is ahead of our view
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash_b]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash_b], ValidationVersion::V1).await;
|
||||
|
||||
// Send our view update to include a new head
|
||||
overseer_send(
|
||||
@@ -1240,7 +1531,7 @@ fn race_condition_in_local_vs_remote_view_update() {
|
||||
.collect();
|
||||
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone());
|
||||
send_message_from_peer(overseer, peer, Versioned::V1(msg.clone())).await;
|
||||
send_message_from_peer(overseer, peer, msg.clone()).await;
|
||||
|
||||
// This will handle pending messages being processed
|
||||
let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]);
|
||||
@@ -1257,8 +1548,8 @@ fn race_condition_in_local_vs_remote_view_update() {
|
||||
claimed_candidate_index,
|
||||
tx,
|
||||
)) => {
|
||||
assert_eq!(assignment, assignments[i].0);
|
||||
assert_eq!(claimed_candidate_index, assignments[i].1);
|
||||
assert_eq!(assignment, assignments[i].0.clone().into());
|
||||
assert_eq!(claimed_candidate_index, assignments[i].1.into());
|
||||
tx.send(AssignmentCheckResult::Accepted).unwrap();
|
||||
}
|
||||
);
|
||||
@@ -1283,7 +1574,7 @@ fn propagates_locally_generated_assignment_to_both_dimensions() {
|
||||
|
||||
// Connect all peers.
|
||||
for (peer, _) in &peers {
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
}
|
||||
|
||||
// Set up a gossip topology.
|
||||
@@ -1325,7 +1616,10 @@ fn propagates_locally_generated_assignment_to_both_dimensions() {
|
||||
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_index.into(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1388,7 +1682,7 @@ fn propagates_assignments_along_unshared_dimension() {
|
||||
|
||||
// Connect all peers.
|
||||
for (peer, _) in &peers {
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
}
|
||||
|
||||
// Set up a gossip topology.
|
||||
@@ -1424,7 +1718,7 @@ fn propagates_assignments_along_unshared_dimension() {
|
||||
|
||||
// Issuer of the message is important, not the peer we receive from.
|
||||
// 99 deliberately chosen because it's not in X or Y.
|
||||
send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peers[99].0, msg).await;
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||
@@ -1473,7 +1767,7 @@ fn propagates_assignments_along_unshared_dimension() {
|
||||
|
||||
// Issuer of the message is important, not the peer we receive from.
|
||||
// 99 deliberately chosen because it's not in X or Y.
|
||||
send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peers[99].0, msg).await;
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||
@@ -1530,7 +1824,7 @@ fn propagates_to_required_after_connect() {
|
||||
// Connect all peers except omitted.
|
||||
for (i, (peer, _)) in peers.iter().enumerate() {
|
||||
if !omitted.contains(&i) {
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1573,7 +1867,10 @@ fn propagates_to_required_after_connect() {
|
||||
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_index.into(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1619,7 +1916,7 @@ fn propagates_to_required_after_connect() {
|
||||
);
|
||||
|
||||
for i in omitted.iter().copied() {
|
||||
setup_peer_with_view(overseer, &peers[i].0, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, &peers[i].0, view![hash], ValidationVersion::V1).await;
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
@@ -1668,7 +1965,7 @@ fn sends_to_more_peers_after_getting_topology() {
|
||||
|
||||
// Connect all peers except omitted.
|
||||
for (peer, _) in &peers {
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
}
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
@@ -1698,7 +1995,10 @@ fn sends_to_more_peers_after_getting_topology() {
|
||||
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_index.into(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1820,7 +2120,7 @@ fn originator_aggression_l1() {
|
||||
|
||||
// Connect all peers except omitted.
|
||||
for (peer, _) in &peers {
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
}
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
@@ -1857,7 +2157,10 @@ fn originator_aggression_l1() {
|
||||
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert.clone(), candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(
|
||||
cert.clone().into(),
|
||||
candidate_index.into(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -1979,7 +2282,7 @@ fn non_originator_aggression_l1() {
|
||||
|
||||
// Connect all peers except omitted.
|
||||
for (peer, _) in &peers {
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
}
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
@@ -2008,12 +2311,12 @@ fn non_originator_aggression_l1() {
|
||||
)
|
||||
.await;
|
||||
|
||||
let assignments = vec![(cert.clone(), candidate_index)];
|
||||
let assignments = vec![(cert.clone().into(), candidate_index)];
|
||||
let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone());
|
||||
|
||||
// Issuer of the message is important, not the peer we receive from.
|
||||
// 99 deliberately chosen because it's not in X or Y.
|
||||
send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peers[99].0, msg).await;
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||
@@ -2084,7 +2387,7 @@ fn non_originator_aggression_l2() {
|
||||
|
||||
// Connect all peers except omitted.
|
||||
for (peer, _) in &peers {
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
}
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
@@ -2118,7 +2421,7 @@ fn non_originator_aggression_l2() {
|
||||
|
||||
// Issuer of the message is important, not the peer we receive from.
|
||||
// 99 deliberately chosen because it's not in X or Y.
|
||||
send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peers[99].0, msg).await;
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||
@@ -2249,7 +2552,7 @@ fn resends_messages_periodically() {
|
||||
|
||||
// Connect all peers.
|
||||
for (peer, _) in &peers {
|
||||
setup_peer_with_view(overseer, peer, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await;
|
||||
}
|
||||
|
||||
// Set up a gossip topology.
|
||||
@@ -2284,7 +2587,7 @@ fn resends_messages_periodically() {
|
||||
|
||||
// Issuer of the message is important, not the peer we receive from.
|
||||
// 99 deliberately chosen because it's not in X or Y.
|
||||
send_message_from_peer(overseer, &peers[99].0, Versioned::V1(msg)).await;
|
||||
send_message_from_peer(overseer, &peers[99].0, msg).await;
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment(
|
||||
@@ -2388,9 +2691,9 @@ fn import_versioned_approval() {
|
||||
let _ = test_harness(state, |mut virtual_overseer| async move {
|
||||
let overseer = &mut virtual_overseer;
|
||||
// All peers are aware of relay parent.
|
||||
setup_peer_with_view(overseer, &peer_a, ValidationVersion::V2, view![hash]).await;
|
||||
setup_peer_with_view(overseer, &peer_b, ValidationVersion::V1, view![hash]).await;
|
||||
setup_peer_with_view(overseer, &peer_c, ValidationVersion::V2, view![hash]).await;
|
||||
setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V2).await;
|
||||
setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await;
|
||||
setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V2).await;
|
||||
|
||||
// new block `hash_a` with 1 candidates
|
||||
let meta = BlockApprovalMeta {
|
||||
@@ -2410,7 +2713,7 @@ fn import_versioned_approval() {
|
||||
let cert = fake_assignment_cert(hash, validator_index);
|
||||
overseer_send(
|
||||
overseer,
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert, candidate_index),
|
||||
ApprovalDistributionMessage::DistributeAssignment(cert.into(), candidate_index.into()),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -2451,7 +2754,7 @@ fn import_versioned_approval() {
|
||||
signature: dummy_signature(),
|
||||
};
|
||||
let msg = protocol_v2::ApprovalDistributionMessage::Approvals(vec![approval.clone()]);
|
||||
send_message_from_peer(overseer, &peer_a, Versioned::V2(msg)).await;
|
||||
send_message_from_peer_v2(overseer, &peer_a, msg).await;
|
||||
|
||||
assert_matches!(
|
||||
overseer_recv(overseer).await,
|
||||
@@ -2512,7 +2815,9 @@ fn batch_test_round(message_count: usize) {
|
||||
let validators = 0..message_count;
|
||||
let assignments: Vec<_> = validators
|
||||
.clone()
|
||||
.map(|index| (fake_assignment_cert(Hash::zero(), ValidatorIndex(index as u32)), 0))
|
||||
.map(|index| {
|
||||
(fake_assignment_cert(Hash::zero(), ValidatorIndex(index as u32)).into(), 0.into())
|
||||
})
|
||||
.collect();
|
||||
|
||||
let approvals: Vec<_> = validators
|
||||
@@ -2525,9 +2830,18 @@ fn batch_test_round(message_count: usize) {
|
||||
.collect();
|
||||
|
||||
let peer = PeerId::random();
|
||||
send_assignments_batched(&mut sender, assignments.clone(), peer, ValidationVersion::V1)
|
||||
.await;
|
||||
send_approvals_batched(&mut sender, approvals.clone(), peer, ValidationVersion::V1).await;
|
||||
send_assignments_batched(
|
||||
&mut sender,
|
||||
assignments.clone(),
|
||||
&vec![(peer, ValidationVersion::V1.into())],
|
||||
)
|
||||
.await;
|
||||
send_approvals_batched(
|
||||
&mut sender,
|
||||
approvals.clone(),
|
||||
&vec![(peer, ValidationVersion::V1.into())],
|
||||
)
|
||||
.await;
|
||||
|
||||
// Check expected assignments batches.
|
||||
for assignment_index in (0..assignments.len()).step_by(super::MAX_ASSIGNMENT_BATCH_SIZE) {
|
||||
@@ -2549,7 +2863,7 @@ fn batch_test_round(message_count: usize) {
|
||||
assert_eq!(peers.len(), 1);
|
||||
|
||||
for (message_index, assignment) in sent_assignments.iter().enumerate() {
|
||||
assert_eq!(assignment.0, assignments[assignment_index + message_index].0);
|
||||
assert_eq!(assignment.0, assignments[assignment_index + message_index].0.clone().try_into().unwrap());
|
||||
assert_eq!(assignment.1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,14 +25,15 @@
|
||||
use always_assert::never;
|
||||
use futures::{channel::oneshot, FutureExt};
|
||||
|
||||
use net_protocol::filter_by_peer_version;
|
||||
use polkadot_node_network_protocol::{
|
||||
self as net_protocol,
|
||||
grid_topology::{
|
||||
GridNeighbors, RandomRouting, RequiredRouting, SessionBoundGridTopologyStorage,
|
||||
},
|
||||
peer_set::{ProtocolVersion, ValidationVersion},
|
||||
v1 as protocol_v1, v2 as protocol_v2, OurView, PeerId, UnifiedReputationChange as Rep,
|
||||
Versioned, View,
|
||||
v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, OurView, PeerId,
|
||||
UnifiedReputationChange as Rep, Versioned, View,
|
||||
};
|
||||
use polkadot_node_subsystem::{
|
||||
jaeger, messages::*, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan,
|
||||
@@ -101,6 +102,11 @@ impl BitfieldGossipMessage {
|
||||
self.relay_parent,
|
||||
self.signed_availability.into(),
|
||||
)),
|
||||
Some(ValidationVersion::VStaging) =>
|
||||
Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield(
|
||||
self.relay_parent,
|
||||
self.signed_availability.into(),
|
||||
)),
|
||||
None => {
|
||||
never!("Peers should only have supported protocol versions.");
|
||||
|
||||
@@ -131,9 +137,9 @@ pub struct PeerData {
|
||||
|
||||
/// Data used to track information of peers and relay parents the
|
||||
/// overseer ordered us to work on.
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Default)]
|
||||
struct ProtocolState {
|
||||
/// Track all active peers and their views
|
||||
/// Track all active peer views and protocol versions
|
||||
/// to determine what is relevant to them.
|
||||
peer_data: HashMap<PeerId, PeerData>,
|
||||
|
||||
@@ -492,17 +498,13 @@ async fn relay_message<Context>(
|
||||
} else {
|
||||
let _span = span.child("gossip");
|
||||
|
||||
let filter_by_version = |peers: &[(PeerId, ProtocolVersion)],
|
||||
version: ValidationVersion| {
|
||||
peers
|
||||
.iter()
|
||||
.filter(|(_, v)| v == &version.into())
|
||||
.map(|(peer_id, _)| *peer_id)
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let v1_interested_peers =
|
||||
filter_by_peer_version(&interested_peers, ValidationVersion::V1.into());
|
||||
let v2_interested_peers =
|
||||
filter_by_peer_version(&interested_peers, ValidationVersion::V2.into());
|
||||
|
||||
let v1_interested_peers = filter_by_version(&interested_peers, ValidationVersion::V1);
|
||||
let v2_interested_peers = filter_by_version(&interested_peers, ValidationVersion::V2);
|
||||
let vstaging_interested_peers =
|
||||
filter_by_peer_version(&interested_peers, ValidationVersion::VStaging.into());
|
||||
|
||||
if !v1_interested_peers.is_empty() {
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
@@ -515,7 +517,15 @@ async fn relay_message<Context>(
|
||||
if !v2_interested_peers.is_empty() {
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
v2_interested_peers,
|
||||
message.into_validation_protocol(ValidationVersion::V2.into()),
|
||||
message.clone().into_validation_protocol(ValidationVersion::V2.into()),
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
if !vstaging_interested_peers.is_empty() {
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
vstaging_interested_peers,
|
||||
message.into_validation_protocol(ValidationVersion::VStaging.into()),
|
||||
))
|
||||
.await
|
||||
}
|
||||
@@ -540,6 +550,10 @@ async fn process_incoming_peer_message<Context>(
|
||||
Versioned::V2(protocol_v2::BitfieldDistributionMessage::Bitfield(
|
||||
relay_parent,
|
||||
bitfield,
|
||||
)) |
|
||||
Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield(
|
||||
relay_parent,
|
||||
bitfield,
|
||||
)) => (relay_parent, bitfield),
|
||||
};
|
||||
|
||||
@@ -774,9 +788,11 @@ async fn handle_network_msg<Context>(
|
||||
handle_peer_view_change(ctx, state, new_peer, old_view, rng).await;
|
||||
}
|
||||
},
|
||||
NetworkBridgeEvent::PeerViewChange(peerid, new_view) => {
|
||||
gum::trace!(target: LOG_TARGET, ?peerid, ?new_view, "Peer view change");
|
||||
handle_peer_view_change(ctx, state, peerid, new_view, rng).await;
|
||||
NetworkBridgeEvent::PeerViewChange(peer_id, new_view) => {
|
||||
gum::trace!(target: LOG_TARGET, ?peer_id, ?new_view, "Peer view change");
|
||||
if state.peer_data.get(&peer_id).is_some() {
|
||||
handle_peer_view_change(ctx, state, peer_id, new_view, rng).await;
|
||||
}
|
||||
},
|
||||
NetworkBridgeEvent::OurViewChange(new_view) => {
|
||||
gum::trace!(target: LOG_TARGET, ?new_view, "Our view change");
|
||||
|
||||
@@ -28,23 +28,129 @@ use sc_network::{
|
||||
};
|
||||
|
||||
use polkadot_node_network_protocol::{
|
||||
peer_set::{PeerSet, PeerSetProtocolNames, ProtocolVersion},
|
||||
peer_set::{
|
||||
CollationVersion, PeerSet, PeerSetProtocolNames, ProtocolVersion, ValidationVersion,
|
||||
},
|
||||
request_response::{OutgoingRequest, Recipient, ReqProtocolNames, Requests},
|
||||
PeerId,
|
||||
v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, PeerId,
|
||||
};
|
||||
use polkadot_primitives::{AuthorityDiscoveryId, Block, Hash};
|
||||
|
||||
use crate::validator_discovery::AuthorityDiscovery;
|
||||
use crate::{metrics::Metrics, validator_discovery::AuthorityDiscovery, WireMessage};
|
||||
|
||||
// network bridge network abstraction log target
|
||||
const LOG_TARGET: &'static str = "parachain::network-bridge-net";
|
||||
|
||||
/// Send a message to the network.
|
||||
// Helper function to send a validation v1 message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_validation_message_v1(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v1::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation v1 message to peers",);
|
||||
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::V1.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to send a validation vstaging message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_validation_message_vstaging(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_vstaging::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation vstaging message to peers",);
|
||||
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::VStaging.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to send a validation v2 message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_validation_message_v2(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v2::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::V2.into(),
|
||||
protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to send a collation v1 message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_collation_message_v1(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v1::CollationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Collation,
|
||||
CollationVersion::V1.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to send a collation v2 message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_collation_message_v2(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v2::CollationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Collation,
|
||||
CollationVersion::V2.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
/// Lower level function that sends a message to the network using the main protocol version.
|
||||
///
|
||||
/// This function is only used internally by the network-bridge, which is responsible to only send
|
||||
/// messages that are compatible with the passed peer set, as that is currently not enforced by
|
||||
/// this function. These are messages of type `WireMessage` parameterized on the matching type.
|
||||
pub(crate) fn send_message<M>(
|
||||
fn send_message<M>(
|
||||
net: &mut impl Network,
|
||||
mut peers: Vec<PeerId>,
|
||||
peer_set: PeerSet,
|
||||
@@ -65,6 +171,17 @@ pub(crate) fn send_message<M>(
|
||||
encoded
|
||||
};
|
||||
|
||||
// optimization: generate the protocol name once.
|
||||
let protocol_name = protocol_names.get_name(peer_set, version);
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
?peers,
|
||||
?version,
|
||||
?protocol_name,
|
||||
?message,
|
||||
"Sending message to peers",
|
||||
);
|
||||
|
||||
// optimization: avoid cloning the message for the last peer in the
|
||||
// list. The message payload can be quite large. If the underlying
|
||||
// network used `Bytes` this would not be necessary.
|
||||
|
||||
@@ -21,6 +21,7 @@ use super::*;
|
||||
use always_assert::never;
|
||||
use bytes::Bytes;
|
||||
use futures::stream::{BoxStream, StreamExt};
|
||||
use net_protocol::filter_by_peer_version;
|
||||
use parity_scale_codec::{Decode, DecodeAll};
|
||||
|
||||
use sc_network::Event as NetworkEvent;
|
||||
@@ -33,8 +34,8 @@ use polkadot_node_network_protocol::{
|
||||
CollationVersion, PeerSet, PeerSetProtocolNames, PerPeerSet, ProtocolVersion,
|
||||
ValidationVersion,
|
||||
},
|
||||
v1 as protocol_v1, v2 as protocol_v2, ObservedRole, OurView, PeerId,
|
||||
UnifiedReputationChange as Rep, View,
|
||||
v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, ObservedRole, OurView,
|
||||
PeerId, UnifiedReputationChange as Rep, View,
|
||||
};
|
||||
|
||||
use polkadot_node_subsystem::{
|
||||
@@ -64,9 +65,11 @@ use super::validator_discovery;
|
||||
/// Actual interfacing to the network based on the `Network` trait.
|
||||
///
|
||||
/// Defines the `Network` trait with an implementation for an `Arc<NetworkService>`.
|
||||
use crate::network::{send_message, Network};
|
||||
|
||||
use crate::network::get_peer_id_by_authority_id;
|
||||
use crate::network::{
|
||||
send_collation_message_v1, send_collation_message_v2, send_validation_message_v1,
|
||||
send_validation_message_v2, send_validation_message_vstaging, Network,
|
||||
};
|
||||
use crate::{network::get_peer_id_by_authority_id, WireMessage};
|
||||
|
||||
use super::metrics::Metrics;
|
||||
|
||||
@@ -251,22 +254,27 @@ where
|
||||
match ValidationVersion::try_from(version)
|
||||
.expect("try_get_protocol has already checked version is known; qed")
|
||||
{
|
||||
ValidationVersion::V1 => send_message(
|
||||
ValidationVersion::V1 => send_validation_message_v1(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
PeerSet::Validation,
|
||||
version,
|
||||
&peerset_protocol_names,
|
||||
WireMessage::<protocol_v1::ValidationProtocol>::ViewUpdate(
|
||||
local_view,
|
||||
),
|
||||
&metrics,
|
||||
),
|
||||
ValidationVersion::V2 => send_message(
|
||||
ValidationVersion::VStaging => send_validation_message_vstaging(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
&peerset_protocol_names,
|
||||
WireMessage::<protocol_vstaging::ValidationProtocol>::ViewUpdate(
|
||||
local_view,
|
||||
),
|
||||
&metrics,
|
||||
),
|
||||
ValidationVersion::V2 => send_validation_message_v2(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
PeerSet::Validation,
|
||||
version,
|
||||
&peerset_protocol_names,
|
||||
WireMessage::<protocol_v2::ValidationProtocol>::ViewUpdate(
|
||||
local_view,
|
||||
@@ -293,22 +301,18 @@ where
|
||||
match CollationVersion::try_from(version)
|
||||
.expect("try_get_protocol has already checked version is known; qed")
|
||||
{
|
||||
CollationVersion::V1 => send_message(
|
||||
CollationVersion::V1 => send_collation_message_v1(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
PeerSet::Collation,
|
||||
version,
|
||||
&peerset_protocol_names,
|
||||
WireMessage::<protocol_v1::CollationProtocol>::ViewUpdate(
|
||||
local_view,
|
||||
),
|
||||
&metrics,
|
||||
),
|
||||
CollationVersion::V2 => send_message(
|
||||
CollationVersion::V2 => send_collation_message_v2(
|
||||
&mut network_service,
|
||||
vec![peer],
|
||||
PeerSet::Collation,
|
||||
version,
|
||||
&peerset_protocol_names,
|
||||
WireMessage::<protocol_v2::CollationProtocol>::ViewUpdate(
|
||||
local_view,
|
||||
@@ -386,8 +390,16 @@ where
|
||||
.filter_map(|(protocol, msg_bytes)| {
|
||||
// version doesn't matter because we always receive on the 'correct'
|
||||
// protocol name, not the negotiated fallback.
|
||||
let (peer_set, _version) =
|
||||
let (peer_set, version) =
|
||||
peerset_protocol_names.try_get_protocol(protocol)?;
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
?peer_set,
|
||||
?protocol,
|
||||
?version,
|
||||
"Received notification"
|
||||
);
|
||||
|
||||
if peer_set == PeerSet::Validation {
|
||||
if expected_versions[PeerSet::Validation].is_none() {
|
||||
return Some(Err(UNCONNECTED_PEERSET_COST))
|
||||
@@ -474,6 +486,16 @@ where
|
||||
v_messages,
|
||||
&metrics,
|
||||
)
|
||||
} else if expected_versions[PeerSet::Validation] ==
|
||||
Some(ValidationVersion::VStaging.into())
|
||||
{
|
||||
handle_peer_messages::<protocol_vstaging::ValidationProtocol, _>(
|
||||
remote,
|
||||
PeerSet::Validation,
|
||||
&mut shared.0.lock().validation_peers,
|
||||
v_messages,
|
||||
&metrics,
|
||||
)
|
||||
} else {
|
||||
gum::warn!(
|
||||
target: LOG_TARGET,
|
||||
@@ -815,15 +837,16 @@ fn update_our_view<Net, Context>(
|
||||
)
|
||||
};
|
||||
|
||||
let filter_by_version = |peers: &[(PeerId, ProtocolVersion)], version| {
|
||||
peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::<Vec<_>>()
|
||||
};
|
||||
let v1_validation_peers =
|
||||
filter_by_peer_version(&validation_peers, ValidationVersion::V1.into());
|
||||
let v1_collation_peers = filter_by_peer_version(&collation_peers, CollationVersion::V1.into());
|
||||
|
||||
let v1_validation_peers = filter_by_version(&validation_peers, ValidationVersion::V1.into());
|
||||
let v1_collation_peers = filter_by_version(&collation_peers, CollationVersion::V1.into());
|
||||
let v2_validation_peers =
|
||||
filter_by_peer_version(&validation_peers, ValidationVersion::V2.into());
|
||||
let v2_collation_peers = filter_by_peer_version(&collation_peers, CollationVersion::V2.into());
|
||||
|
||||
let v2_validation_peers = filter_by_version(&validation_peers, ValidationVersion::V2.into());
|
||||
let v2_collation_peers = filter_by_version(&collation_peers, ValidationVersion::V2.into());
|
||||
let vstaging_validation_peers =
|
||||
filter_by_peer_version(&validation_peers, ValidationVersion::VStaging.into());
|
||||
|
||||
send_validation_message_v1(
|
||||
net,
|
||||
@@ -853,7 +876,15 @@ fn update_our_view<Net, Context>(
|
||||
net,
|
||||
v2_collation_peers,
|
||||
peerset_protocol_names,
|
||||
WireMessage::ViewUpdate(new_view),
|
||||
WireMessage::ViewUpdate(new_view.clone()),
|
||||
metrics,
|
||||
);
|
||||
|
||||
send_validation_message_vstaging(
|
||||
net,
|
||||
vstaging_validation_peers,
|
||||
peerset_protocol_names,
|
||||
WireMessage::ViewUpdate(new_view.clone()),
|
||||
metrics,
|
||||
);
|
||||
|
||||
@@ -926,78 +957,6 @@ fn handle_peer_messages<RawMessage: Decode, OutMessage: From<RawMessage>>(
|
||||
(outgoing_events, reports)
|
||||
}
|
||||
|
||||
fn send_validation_message_v1(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v1::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::V1.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
fn send_collation_message_v1(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v1::CollationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Collation,
|
||||
CollationVersion::V1.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
fn send_validation_message_v2(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v2::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::V2.into(),
|
||||
protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
fn send_collation_message_v2(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v2::CollationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Collation,
|
||||
CollationVersion::V2.into(),
|
||||
protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
async fn dispatch_validation_event_to_all(
|
||||
event: NetworkBridgeEvent<net_protocol::VersionedValidationProtocol>,
|
||||
ctx: &mut impl overseer::NetworkBridgeRxSenderTrait,
|
||||
|
||||
@@ -1248,6 +1248,9 @@ fn network_protocol_versioning_view_update() {
|
||||
ValidationVersion::V2 =>
|
||||
WireMessage::<protocol_v2::ValidationProtocol>::ViewUpdate(view.clone())
|
||||
.encode(),
|
||||
ValidationVersion::VStaging =>
|
||||
WireMessage::<protocol_vstaging::ValidationProtocol>::ViewUpdate(view.clone())
|
||||
.encode(),
|
||||
};
|
||||
assert_network_actions_contains(
|
||||
&actions,
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
use super::*;
|
||||
|
||||
use polkadot_node_network_protocol::{
|
||||
peer_set::{CollationVersion, PeerSet, PeerSetProtocolNames, ValidationVersion},
|
||||
request_response::ReqProtocolNames,
|
||||
v1 as protocol_v1, v2 as protocol_v2, PeerId, Versioned,
|
||||
peer_set::PeerSetProtocolNames, request_response::ReqProtocolNames, Versioned,
|
||||
};
|
||||
|
||||
use polkadot_node_subsystem::{
|
||||
@@ -41,7 +39,10 @@ use crate::validator_discovery;
|
||||
/// Actual interfacing to the network based on the `Network` trait.
|
||||
///
|
||||
/// Defines the `Network` trait with an implementation for an `Arc<NetworkService>`.
|
||||
use crate::network::{send_message, Network};
|
||||
use crate::network::{
|
||||
send_collation_message_v1, send_collation_message_v2, send_validation_message_v1,
|
||||
send_validation_message_v2, send_validation_message_vstaging, Network,
|
||||
};
|
||||
|
||||
use crate::metrics::Metrics;
|
||||
|
||||
@@ -187,6 +188,7 @@ where
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
action = "SendValidationMessages",
|
||||
?msg,
|
||||
num_messages = 1usize,
|
||||
);
|
||||
|
||||
@@ -198,6 +200,13 @@ where
|
||||
WireMessage::ProtocolMessage(msg),
|
||||
&metrics,
|
||||
),
|
||||
Versioned::VStaging(msg) => send_validation_message_vstaging(
|
||||
&mut network_service,
|
||||
peers,
|
||||
peerset_protocol_names,
|
||||
WireMessage::ProtocolMessage(msg),
|
||||
&metrics,
|
||||
),
|
||||
Versioned::V2(msg) => send_validation_message_v2(
|
||||
&mut network_service,
|
||||
peers,
|
||||
@@ -212,6 +221,7 @@ where
|
||||
target: LOG_TARGET,
|
||||
action = "SendValidationMessages",
|
||||
num_messages = %msgs.len(),
|
||||
?msgs,
|
||||
);
|
||||
|
||||
for (peers, msg) in msgs {
|
||||
@@ -223,6 +233,13 @@ where
|
||||
WireMessage::ProtocolMessage(msg),
|
||||
&metrics,
|
||||
),
|
||||
Versioned::VStaging(msg) => send_validation_message_vstaging(
|
||||
&mut network_service,
|
||||
peers,
|
||||
peerset_protocol_names,
|
||||
WireMessage::ProtocolMessage(msg),
|
||||
&metrics,
|
||||
),
|
||||
Versioned::V2(msg) => send_validation_message_v2(
|
||||
&mut network_service,
|
||||
peers,
|
||||
@@ -248,7 +265,7 @@ where
|
||||
WireMessage::ProtocolMessage(msg),
|
||||
&metrics,
|
||||
),
|
||||
Versioned::V2(msg) => send_collation_message_v2(
|
||||
Versioned::V2(msg) | Versioned::VStaging(msg) => send_collation_message_v2(
|
||||
&mut network_service,
|
||||
peers,
|
||||
peerset_protocol_names,
|
||||
@@ -273,7 +290,7 @@ where
|
||||
WireMessage::ProtocolMessage(msg),
|
||||
&metrics,
|
||||
),
|
||||
Versioned::V2(msg) => send_collation_message_v2(
|
||||
Versioned::V2(msg) | Versioned::VStaging(msg) => send_collation_message_v2(
|
||||
&mut network_service,
|
||||
peers,
|
||||
peerset_protocol_names,
|
||||
@@ -386,75 +403,3 @@ where
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_validation_message_v1(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v1::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::V1.into(),
|
||||
protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
fn send_collation_message_v1(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v1::CollationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Collation,
|
||||
CollationVersion::V1.into(),
|
||||
protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
fn send_validation_message_v2(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v2::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::V2.into(),
|
||||
protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
fn send_collation_message_v2(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v2::CollationProtocol>,
|
||||
metrics: &Metrics,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Collation,
|
||||
CollationVersion::V2.into(),
|
||||
protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ use std::collections::HashSet;
|
||||
use sc_network::{Event as NetworkEvent, IfDisconnected, ProtocolName, ReputationChange};
|
||||
|
||||
use polkadot_node_network_protocol::{
|
||||
peer_set::PeerSetProtocolNames,
|
||||
peer_set::{PeerSetProtocolNames, ValidationVersion},
|
||||
request_response::{outgoing::Requests, ReqProtocolNames},
|
||||
ObservedRole, Versioned,
|
||||
v1 as protocol_v1, v2 as protocol_v2, ObservedRole, Versioned,
|
||||
};
|
||||
use polkadot_node_subsystem::{FromOrchestra, OverseerSignal};
|
||||
use polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle;
|
||||
@@ -356,7 +356,6 @@ fn network_protocol_versioning_send() {
|
||||
}
|
||||
|
||||
// send a validation protocol message.
|
||||
|
||||
{
|
||||
let approval_distribution_message =
|
||||
protocol_v2::ApprovalDistributionMessage::Approvals(Vec::new());
|
||||
|
||||
@@ -880,7 +880,9 @@ async fn handle_incoming_peer_message<Context>(
|
||||
use protocol_v2::CollatorProtocolMessage as V2;
|
||||
|
||||
match msg {
|
||||
Versioned::V1(V1::Declare(..)) | Versioned::V2(V2::Declare(..)) => {
|
||||
Versioned::V1(V1::Declare(..)) |
|
||||
Versioned::V2(V2::Declare(..)) |
|
||||
Versioned::VStaging(V2::Declare(..)) => {
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
?origin,
|
||||
@@ -891,7 +893,9 @@ async fn handle_incoming_peer_message<Context>(
|
||||
ctx.send_message(NetworkBridgeTxMessage::DisconnectPeer(origin, PeerSet::Collation))
|
||||
.await;
|
||||
},
|
||||
Versioned::V1(V1::AdvertiseCollation(_)) | Versioned::V2(V2::AdvertiseCollation { .. }) => {
|
||||
Versioned::V1(V1::AdvertiseCollation(_)) |
|
||||
Versioned::V2(V2::AdvertiseCollation { .. }) |
|
||||
Versioned::VStaging(V2::AdvertiseCollation { .. }) => {
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
?origin,
|
||||
@@ -906,7 +910,8 @@ async fn handle_incoming_peer_message<Context>(
|
||||
.await;
|
||||
},
|
||||
Versioned::V1(V1::CollationSeconded(relay_parent, statement)) |
|
||||
Versioned::V2(V2::CollationSeconded(relay_parent, statement)) => {
|
||||
Versioned::V2(V2::CollationSeconded(relay_parent, statement)) |
|
||||
Versioned::VStaging(V2::CollationSeconded(relay_parent, statement)) => {
|
||||
if !matches!(statement.unchecked_payload(), Statement::Seconded(_)) {
|
||||
gum::warn!(
|
||||
target: LOG_TARGET,
|
||||
|
||||
@@ -776,7 +776,8 @@ async fn process_incoming_peer_message<Context>(
|
||||
|
||||
match msg {
|
||||
Versioned::V1(V1::Declare(collator_id, para_id, signature)) |
|
||||
Versioned::V2(V2::Declare(collator_id, para_id, signature)) => {
|
||||
Versioned::V2(V2::Declare(collator_id, para_id, signature)) |
|
||||
Versioned::VStaging(V2::Declare(collator_id, para_id, signature)) => {
|
||||
if collator_peer_id(&state.peer_data, &collator_id).is_some() {
|
||||
modify_reputation(
|
||||
&mut state.reputation,
|
||||
@@ -892,6 +893,11 @@ async fn process_incoming_peer_message<Context>(
|
||||
relay_parent,
|
||||
candidate_hash,
|
||||
parent_head_data_hash,
|
||||
}) |
|
||||
Versioned::VStaging(V2::AdvertiseCollation {
|
||||
relay_parent,
|
||||
candidate_hash,
|
||||
parent_head_data_hash,
|
||||
}) =>
|
||||
if let Err(err) = handle_advertisement(
|
||||
ctx.sender(),
|
||||
@@ -915,7 +921,9 @@ async fn process_incoming_peer_message<Context>(
|
||||
modify_reputation(&mut state.reputation, ctx.sender(), origin, rep).await;
|
||||
}
|
||||
},
|
||||
Versioned::V1(V1::CollationSeconded(..)) | Versioned::V2(V2::CollationSeconded(..)) => {
|
||||
Versioned::V1(V1::CollationSeconded(..)) |
|
||||
Versioned::V2(V2::CollationSeconded(..)) |
|
||||
Versioned::VStaging(V2::CollationSeconded(..)) => {
|
||||
gum::warn!(
|
||||
target: LOG_TARGET,
|
||||
peer_id = ?origin,
|
||||
|
||||
@@ -477,6 +477,7 @@ where
|
||||
match message {
|
||||
Versioned::V1(m) => match m {},
|
||||
Versioned::V2(m) => match m {},
|
||||
Versioned::VStaging(m) => match m {},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -27,3 +27,6 @@ bitvec = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
rand_chacha = "0.3.1"
|
||||
|
||||
[features]
|
||||
network-protocol-staging = []
|
||||
|
||||
@@ -253,25 +253,29 @@ impl View {
|
||||
|
||||
/// A protocol-versioned type.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Versioned<V1, V2> {
|
||||
pub enum Versioned<V1, V2, VStaging = V2> {
|
||||
/// V1 type.
|
||||
V1(V1),
|
||||
/// V2 type.
|
||||
V2(V2),
|
||||
/// VStaging type
|
||||
VStaging(VStaging),
|
||||
}
|
||||
|
||||
impl<V1: Clone, V2: Clone> Versioned<&'_ V1, &'_ V2> {
|
||||
impl<V1: Clone, V2: Clone, VStaging: Clone> Versioned<&'_ V1, &'_ V2, &'_ VStaging> {
|
||||
/// Convert to a fully-owned version of the message.
|
||||
pub fn clone_inner(&self) -> Versioned<V1, V2> {
|
||||
pub fn clone_inner(&self) -> Versioned<V1, V2, VStaging> {
|
||||
match *self {
|
||||
Versioned::V1(inner) => Versioned::V1(inner.clone()),
|
||||
Versioned::V2(inner) => Versioned::V2(inner.clone()),
|
||||
Versioned::VStaging(inner) => Versioned::VStaging(inner.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// All supported versions of the validation protocol message.
|
||||
pub type VersionedValidationProtocol = Versioned<v1::ValidationProtocol, v2::ValidationProtocol>;
|
||||
pub type VersionedValidationProtocol =
|
||||
Versioned<v1::ValidationProtocol, v2::ValidationProtocol, vstaging::ValidationProtocol>;
|
||||
|
||||
impl From<v1::ValidationProtocol> for VersionedValidationProtocol {
|
||||
fn from(v1: v1::ValidationProtocol) -> Self {
|
||||
@@ -285,6 +289,12 @@ impl From<v2::ValidationProtocol> for VersionedValidationProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<vstaging::ValidationProtocol> for VersionedValidationProtocol {
|
||||
fn from(vstaging: vstaging::ValidationProtocol) -> Self {
|
||||
VersionedValidationProtocol::VStaging(vstaging)
|
||||
}
|
||||
}
|
||||
|
||||
/// All supported versions of the collation protocol message.
|
||||
pub type VersionedCollationProtocol = Versioned<v1::CollationProtocol, v2::CollationProtocol>;
|
||||
|
||||
@@ -307,12 +317,12 @@ macro_rules! impl_versioned_full_protocol_from {
|
||||
match versioned_from {
|
||||
Versioned::V1(x) => Versioned::V1(x.into()),
|
||||
Versioned::V2(x) => Versioned::V2(x.into()),
|
||||
Versioned::VStaging(x) => Versioned::VStaging(x.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `TryFrom` for one versioned enum variant into the inner type.
|
||||
/// `$m_ty::$variant(inner) -> Ok(inner)`
|
||||
macro_rules! impl_versioned_try_from {
|
||||
@@ -320,7 +330,8 @@ macro_rules! impl_versioned_try_from {
|
||||
$from:ty,
|
||||
$out:ty,
|
||||
$v1_pat:pat => $v1_out:expr,
|
||||
$v2_pat:pat => $v2_out:expr
|
||||
$v2_pat:pat => $v2_out:expr,
|
||||
$vstaging_pat:pat => $vstaging_out:expr
|
||||
) => {
|
||||
impl TryFrom<$from> for $out {
|
||||
type Error = crate::WrongVariant;
|
||||
@@ -330,6 +341,7 @@ macro_rules! impl_versioned_try_from {
|
||||
match x {
|
||||
Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out)),
|
||||
Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out)),
|
||||
Versioned::VStaging($vstaging_pat) => Ok(Versioned::VStaging($vstaging_out)),
|
||||
_ => Err(crate::WrongVariant),
|
||||
}
|
||||
}
|
||||
@@ -343,6 +355,8 @@ macro_rules! impl_versioned_try_from {
|
||||
match x {
|
||||
Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out.clone())),
|
||||
Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out.clone())),
|
||||
Versioned::VStaging($vstaging_pat) =>
|
||||
Ok(Versioned::VStaging($vstaging_out.clone())),
|
||||
_ => Err(crate::WrongVariant),
|
||||
}
|
||||
}
|
||||
@@ -351,8 +365,11 @@ macro_rules! impl_versioned_try_from {
|
||||
}
|
||||
|
||||
/// Version-annotated messages used by the bitfield distribution subsystem.
|
||||
pub type BitfieldDistributionMessage =
|
||||
Versioned<v1::BitfieldDistributionMessage, v2::BitfieldDistributionMessage>;
|
||||
pub type BitfieldDistributionMessage = Versioned<
|
||||
v1::BitfieldDistributionMessage,
|
||||
v2::BitfieldDistributionMessage,
|
||||
vstaging::BitfieldDistributionMessage,
|
||||
>;
|
||||
impl_versioned_full_protocol_from!(
|
||||
BitfieldDistributionMessage,
|
||||
VersionedValidationProtocol,
|
||||
@@ -362,12 +379,16 @@ impl_versioned_try_from!(
|
||||
VersionedValidationProtocol,
|
||||
BitfieldDistributionMessage,
|
||||
v1::ValidationProtocol::BitfieldDistribution(x) => x,
|
||||
v2::ValidationProtocol::BitfieldDistribution(x) => x
|
||||
v2::ValidationProtocol::BitfieldDistribution(x) => x,
|
||||
vstaging::ValidationProtocol::BitfieldDistribution(x) => x
|
||||
);
|
||||
|
||||
/// Version-annotated messages used by the statement distribution subsystem.
|
||||
pub type StatementDistributionMessage =
|
||||
Versioned<v1::StatementDistributionMessage, v2::StatementDistributionMessage>;
|
||||
pub type StatementDistributionMessage = Versioned<
|
||||
v1::StatementDistributionMessage,
|
||||
v2::StatementDistributionMessage,
|
||||
vstaging::StatementDistributionMessage,
|
||||
>;
|
||||
impl_versioned_full_protocol_from!(
|
||||
StatementDistributionMessage,
|
||||
VersionedValidationProtocol,
|
||||
@@ -377,12 +398,16 @@ impl_versioned_try_from!(
|
||||
VersionedValidationProtocol,
|
||||
StatementDistributionMessage,
|
||||
v1::ValidationProtocol::StatementDistribution(x) => x,
|
||||
v2::ValidationProtocol::StatementDistribution(x) => x
|
||||
v2::ValidationProtocol::StatementDistribution(x) => x,
|
||||
vstaging::ValidationProtocol::StatementDistribution(x) => x
|
||||
);
|
||||
|
||||
/// Version-annotated messages used by the approval distribution subsystem.
|
||||
pub type ApprovalDistributionMessage =
|
||||
Versioned<v1::ApprovalDistributionMessage, v2::ApprovalDistributionMessage>;
|
||||
pub type ApprovalDistributionMessage = Versioned<
|
||||
v1::ApprovalDistributionMessage,
|
||||
v2::ApprovalDistributionMessage,
|
||||
vstaging::ApprovalDistributionMessage,
|
||||
>;
|
||||
impl_versioned_full_protocol_from!(
|
||||
ApprovalDistributionMessage,
|
||||
VersionedValidationProtocol,
|
||||
@@ -392,13 +417,18 @@ impl_versioned_try_from!(
|
||||
VersionedValidationProtocol,
|
||||
ApprovalDistributionMessage,
|
||||
v1::ValidationProtocol::ApprovalDistribution(x) => x,
|
||||
v2::ValidationProtocol::ApprovalDistribution(x) => x
|
||||
v2::ValidationProtocol::ApprovalDistribution(x) => x,
|
||||
vstaging::ValidationProtocol::ApprovalDistribution(x) => x
|
||||
|
||||
);
|
||||
|
||||
/// Version-annotated messages used by the gossip-support subsystem (this is void).
|
||||
pub type GossipSupportNetworkMessage =
|
||||
Versioned<v1::GossipSupportNetworkMessage, v2::GossipSupportNetworkMessage>;
|
||||
pub type GossipSupportNetworkMessage = Versioned<
|
||||
v1::GossipSupportNetworkMessage,
|
||||
v2::GossipSupportNetworkMessage,
|
||||
vstaging::GossipSupportNetworkMessage,
|
||||
>;
|
||||
|
||||
// This is a void enum placeholder, so never gets sent over the wire.
|
||||
impl TryFrom<VersionedValidationProtocol> for GossipSupportNetworkMessage {
|
||||
type Error = WrongVariant;
|
||||
@@ -426,6 +456,7 @@ impl_versioned_try_from!(
|
||||
VersionedCollationProtocol,
|
||||
CollatorProtocolMessage,
|
||||
v1::CollationProtocol::CollatorProtocol(x) => x,
|
||||
v2::CollationProtocol::CollatorProtocol(x) => x,
|
||||
v2::CollationProtocol::CollatorProtocol(x) => x
|
||||
);
|
||||
|
||||
@@ -439,7 +470,7 @@ pub mod v1 {
|
||||
};
|
||||
|
||||
use polkadot_node_primitives::{
|
||||
approval::{IndirectAssignmentCert, IndirectSignedApprovalVote},
|
||||
approval::v1::{IndirectAssignmentCert, IndirectSignedApprovalVote},
|
||||
UncheckedSignedFullStatement,
|
||||
};
|
||||
|
||||
@@ -598,7 +629,7 @@ pub mod v2 {
|
||||
};
|
||||
|
||||
use polkadot_node_primitives::{
|
||||
approval::{IndirectAssignmentCert, IndirectSignedApprovalVote},
|
||||
approval::v1::{IndirectAssignmentCert, IndirectSignedApprovalVote},
|
||||
UncheckedSignedFullStatement,
|
||||
};
|
||||
|
||||
@@ -839,3 +870,64 @@ pub mod v2 {
|
||||
payload
|
||||
}
|
||||
}
|
||||
|
||||
/// vstaging network protocol types, intended to become v3.
|
||||
/// Initial purpose is for chaning ApprovalDistributionMessage to
|
||||
/// include more than one assignment in the message.
|
||||
pub mod vstaging {
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
use polkadot_node_primitives::approval::{
|
||||
v1::IndirectSignedApprovalVote,
|
||||
v2::{CandidateBitfield, IndirectAssignmentCertV2},
|
||||
};
|
||||
|
||||
/// This parts of the protocol did not change from v2, so just alias them in vstaging,
|
||||
/// no reason why they can't be change untill vstaging becomes v3 and is released.
|
||||
pub use super::v2::{
|
||||
declare_signature_payload, BackedCandidateAcknowledgement, BackedCandidateManifest,
|
||||
BitfieldDistributionMessage, GossipSupportNetworkMessage, StatementDistributionMessage,
|
||||
StatementFilter,
|
||||
};
|
||||
|
||||
/// Network messages used by the approval distribution subsystem.
|
||||
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
|
||||
pub enum ApprovalDistributionMessage {
|
||||
/// Assignments for candidates in recent, unfinalized blocks.
|
||||
/// We use a bitfield to reference claimed candidates, where the bit index is equal to
|
||||
/// candidate index.
|
||||
///
|
||||
/// Actually checking the assignment may yield a different result.
|
||||
/// TODO: Look at getting rid of bitfield in the future.
|
||||
#[codec(index = 0)]
|
||||
Assignments(Vec<(IndirectAssignmentCertV2, CandidateBitfield)>),
|
||||
/// Approvals for candidates in some recent, unfinalized block.
|
||||
#[codec(index = 1)]
|
||||
Approvals(Vec<IndirectSignedApprovalVote>),
|
||||
}
|
||||
|
||||
/// All network messages on the validation peer-set.
|
||||
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
|
||||
pub enum ValidationProtocol {
|
||||
/// Bitfield distribution messages
|
||||
#[codec(index = 1)]
|
||||
#[from]
|
||||
BitfieldDistribution(BitfieldDistributionMessage),
|
||||
/// Statement distribution messages
|
||||
#[codec(index = 3)]
|
||||
#[from]
|
||||
StatementDistribution(StatementDistributionMessage),
|
||||
/// Approval distribution messages
|
||||
#[codec(index = 4)]
|
||||
#[from]
|
||||
ApprovalDistribution(ApprovalDistributionMessage),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the subset of `peers` with the specified `version`.
|
||||
pub fn filter_by_peer_version(
|
||||
peers: &[(PeerId, peer_set::ProtocolVersion)],
|
||||
version: peer_set::ProtocolVersion,
|
||||
) -> Vec<PeerId> {
|
||||
peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
@@ -118,10 +118,17 @@ impl PeerSet {
|
||||
/// Networking layer relies on `get_main_version()` being the version
|
||||
/// of the main protocol name reported by [`PeerSetProtocolNames::get_main_name()`].
|
||||
pub fn get_main_version(self) -> ProtocolVersion {
|
||||
#[cfg(not(feature = "network-protocol-staging"))]
|
||||
match self {
|
||||
PeerSet::Validation => ValidationVersion::V2.into(),
|
||||
PeerSet::Collation => CollationVersion::V2.into(),
|
||||
}
|
||||
|
||||
#[cfg(feature = "network-protocol-staging")]
|
||||
match self {
|
||||
PeerSet::Validation => ValidationVersion::VStaging.into(),
|
||||
PeerSet::Collation => CollationVersion::V2.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the max notification size for this peer set.
|
||||
@@ -147,6 +154,8 @@ impl PeerSet {
|
||||
Some("validation/1")
|
||||
} else if version == ValidationVersion::V2.into() {
|
||||
Some("validation/2")
|
||||
} else if version == ValidationVersion::VStaging.into() {
|
||||
Some("validation/3")
|
||||
} else {
|
||||
None
|
||||
},
|
||||
@@ -218,6 +227,9 @@ pub enum ValidationVersion {
|
||||
V1 = 1,
|
||||
/// The second version.
|
||||
V2 = 2,
|
||||
/// The staging version to gather changes
|
||||
/// that before the release become v3.
|
||||
VStaging = 3,
|
||||
}
|
||||
|
||||
/// Supported collation protocol versions. Only versions defined here must be used in the codebase.
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use net_protocol::{filter_by_peer_version, peer_set::ProtocolVersion};
|
||||
use parity_scale_codec::Encode;
|
||||
|
||||
use polkadot_node_network_protocol::{
|
||||
@@ -21,7 +22,8 @@ use polkadot_node_network_protocol::{
|
||||
grid_topology::{GridNeighbors, RequiredRouting, SessionBoundGridTopologyStorage},
|
||||
peer_set::{IsAuthority, PeerSet, ValidationVersion},
|
||||
v1::{self as protocol_v1, StatementMetadata},
|
||||
v2 as protocol_v2, IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View,
|
||||
v2 as protocol_v2, vstaging as protocol_vstaging, IfDisconnected, PeerId,
|
||||
UnifiedReputationChange as Rep, Versioned, View,
|
||||
};
|
||||
use polkadot_node_primitives::{
|
||||
SignedFullStatement, Statement, StatementWithPVD, UncheckedSignedFullStatement,
|
||||
@@ -1061,7 +1063,7 @@ async fn circulate_statement<'a, Context>(
|
||||
"We filter out duplicates above. qed.",
|
||||
);
|
||||
|
||||
let (v1_peers_to_send, v2_peers_to_send) = peers_to_send
|
||||
let (v1_peers_to_send, non_v1_peers_to_send) = peers_to_send
|
||||
.into_iter()
|
||||
.map(|peer_id| {
|
||||
let peer_data =
|
||||
@@ -1073,7 +1075,7 @@ async fn circulate_statement<'a, Context>(
|
||||
})
|
||||
.partition::<Vec<_>, _>(|(_, _, version)| match version {
|
||||
ValidationVersion::V1 => true,
|
||||
ValidationVersion::V2 => false,
|
||||
ValidationVersion::V2 | ValidationVersion::VStaging => false,
|
||||
}); // partition is handy here but not if we add more protocol versions
|
||||
|
||||
let payload = v1_statement_message(relay_parent, stored.statement.clone(), metrics);
|
||||
@@ -1093,6 +1095,22 @@ async fn circulate_statement<'a, Context>(
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
let peers_to_send: Vec<(PeerId, ProtocolVersion)> = non_v1_peers_to_send
|
||||
.iter()
|
||||
.map(|(p, _, version)| (*p, (*version).into()))
|
||||
.collect();
|
||||
|
||||
let peer_needs_dependent_statement = v1_peers_to_send
|
||||
.into_iter()
|
||||
.chain(non_v1_peers_to_send)
|
||||
.filter_map(|(peer, needs_dependent, _)| if needs_dependent { Some(peer) } else { None })
|
||||
.collect();
|
||||
|
||||
let v2_peers_to_send = filter_by_peer_version(&peers_to_send, ValidationVersion::V2.into());
|
||||
let vstaging_to_send =
|
||||
filter_by_peer_version(&peers_to_send, ValidationVersion::VStaging.into());
|
||||
|
||||
if !v2_peers_to_send.is_empty() {
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
@@ -1102,17 +1120,28 @@ async fn circulate_statement<'a, Context>(
|
||||
"Sending statement to v2 peers",
|
||||
);
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
v2_peers_to_send.iter().map(|(p, _, _)| *p).collect(),
|
||||
v2_peers_to_send,
|
||||
compatible_v1_message(ValidationVersion::V2, payload.clone()).into(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
v1_peers_to_send
|
||||
.into_iter()
|
||||
.chain(v2_peers_to_send)
|
||||
.filter_map(|(peer, needs_dependent, _)| if needs_dependent { Some(peer) } else { None })
|
||||
.collect()
|
||||
if !vstaging_to_send.is_empty() {
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
?vstaging_to_send,
|
||||
?relay_parent,
|
||||
statement = ?stored.statement,
|
||||
"Sending statement to vstaging peers",
|
||||
);
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
vstaging_to_send,
|
||||
compatible_v1_message(ValidationVersion::VStaging, payload.clone()).into(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
peer_needs_dependent_statement
|
||||
}
|
||||
|
||||
/// Send all statements about a given candidate hash to a peer.
|
||||
@@ -1442,8 +1471,11 @@ async fn handle_incoming_message<'a, Context>(
|
||||
|
||||
let message = match message {
|
||||
Versioned::V1(m) => m,
|
||||
Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(m)) => m,
|
||||
Versioned::V2(_) => {
|
||||
Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(m)) |
|
||||
Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::V1Compatibility(
|
||||
m,
|
||||
)) => m,
|
||||
Versioned::V2(_) | Versioned::VStaging(_) => {
|
||||
// The higher-level subsystem code is supposed to filter out
|
||||
// all non v1 messages.
|
||||
gum::debug!(
|
||||
@@ -2169,5 +2201,8 @@ fn compatible_v1_message(
|
||||
ValidationVersion::V1 => Versioned::V1(message),
|
||||
ValidationVersion::V2 =>
|
||||
Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(message)),
|
||||
ValidationVersion::VStaging => Versioned::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::V1Compatibility(message),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ use std::time::Duration;
|
||||
|
||||
use polkadot_node_network_protocol::{
|
||||
request_response::{v1 as request_v1, v2::AttestedCandidateRequest, IncomingRequestReceiver},
|
||||
v2 as protocol_v2, Versioned,
|
||||
v2 as protocol_v2, vstaging as protocol_vstaging, Versioned,
|
||||
};
|
||||
use polkadot_node_primitives::StatementWithPVD;
|
||||
use polkadot_node_subsystem::{
|
||||
@@ -399,9 +399,12 @@ impl<R: rand::Rng> StatementDistributionSubsystem<R> {
|
||||
NetworkBridgeEvent::PeerMessage(_, message) => match message {
|
||||
Versioned::V2(
|
||||
protocol_v2::StatementDistributionMessage::V1Compatibility(_),
|
||||
) |
|
||||
Versioned::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::V1Compatibility(_),
|
||||
) => VersionTarget::Legacy,
|
||||
Versioned::V1(_) => VersionTarget::Legacy,
|
||||
Versioned::V2(_) => VersionTarget::Current,
|
||||
Versioned::V2(_) | Versioned::VStaging(_) => VersionTarget::Current,
|
||||
},
|
||||
_ => VersionTarget::Both,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
//! Implementation of the v2 statement distribution protocol,
|
||||
//! designed for asynchronous backing.
|
||||
|
||||
use net_protocol::{filter_by_peer_version, peer_set::ProtocolVersion};
|
||||
use polkadot_node_network_protocol::{
|
||||
self as net_protocol,
|
||||
grid_topology::SessionGridTopology,
|
||||
@@ -28,7 +29,8 @@ use polkadot_node_network_protocol::{
|
||||
MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS,
|
||||
},
|
||||
v2::{self as protocol_v2, StatementFilter},
|
||||
IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View,
|
||||
vstaging as protocol_vstaging, IfDisconnected, PeerId, UnifiedReputationChange as Rep,
|
||||
Versioned, View,
|
||||
};
|
||||
use polkadot_node_primitives::{
|
||||
SignedFullStatementWithPVD, StatementWithPVD as FullStatementWithPVD,
|
||||
@@ -260,6 +262,7 @@ fn connected_validator_peer(
|
||||
|
||||
struct PeerState {
|
||||
view: View,
|
||||
protocol_version: ValidationVersion,
|
||||
implicit_view: HashSet<Hash>,
|
||||
discovery_ids: Option<HashSet<AuthorityDiscoveryId>>,
|
||||
}
|
||||
@@ -332,9 +335,13 @@ pub(crate) async fn handle_network_update<Context>(
|
||||
NetworkBridgeEvent::PeerConnected(peer_id, role, protocol_version, mut authority_ids) => {
|
||||
gum::trace!(target: LOG_TARGET, ?peer_id, ?role, ?protocol_version, "Peer connected");
|
||||
|
||||
if protocol_version != ValidationVersion::V2.into() {
|
||||
let versioned_protocol = if protocol_version != ValidationVersion::V2.into() &&
|
||||
protocol_version != ValidationVersion::VStaging.into()
|
||||
{
|
||||
return
|
||||
}
|
||||
} else {
|
||||
protocol_version.try_into().expect("Qed, we checked above")
|
||||
};
|
||||
|
||||
if let Some(ref mut authority_ids) = authority_ids {
|
||||
authority_ids.retain(|a| match state.authorities.entry(a.clone()) {
|
||||
@@ -361,6 +368,7 @@ pub(crate) async fn handle_network_update<Context>(
|
||||
PeerState {
|
||||
view: View::default(),
|
||||
implicit_view: HashSet::new(),
|
||||
protocol_version: versioned_protocol,
|
||||
discovery_ids: authority_ids,
|
||||
},
|
||||
);
|
||||
@@ -393,17 +401,29 @@ pub(crate) async fn handle_network_update<Context>(
|
||||
net_protocol::StatementDistributionMessage::V1(_) => return,
|
||||
net_protocol::StatementDistributionMessage::V2(
|
||||
protocol_v2::StatementDistributionMessage::V1Compatibility(_),
|
||||
) |
|
||||
net_protocol::StatementDistributionMessage::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::V1Compatibility(_),
|
||||
) => return,
|
||||
net_protocol::StatementDistributionMessage::V2(
|
||||
protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement),
|
||||
) |
|
||||
net_protocol::StatementDistributionMessage::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement),
|
||||
) =>
|
||||
handle_incoming_statement(ctx, state, peer_id, relay_parent, statement, reputation)
|
||||
.await,
|
||||
net_protocol::StatementDistributionMessage::V2(
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateManifest(inner),
|
||||
) |
|
||||
net_protocol::StatementDistributionMessage::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(inner),
|
||||
) => handle_incoming_manifest(ctx, state, peer_id, inner, reputation).await,
|
||||
net_protocol::StatementDistributionMessage::V2(
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateKnown(inner),
|
||||
) |
|
||||
net_protocol::StatementDistributionMessage::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(inner),
|
||||
) => handle_incoming_acknowledgement(ctx, state, peer_id, inner, reputation).await,
|
||||
},
|
||||
NetworkBridgeEvent::PeerViewChange(peer_id, view) =>
|
||||
@@ -709,7 +729,7 @@ async fn send_peer_messages_for_relay_parent<Context>(
|
||||
send_pending_cluster_statements(
|
||||
ctx,
|
||||
relay_parent,
|
||||
&peer,
|
||||
&(peer, peer_data.protocol_version),
|
||||
validator_id,
|
||||
&mut local_validator_state.cluster_tracker,
|
||||
&state.candidates,
|
||||
@@ -721,7 +741,7 @@ async fn send_peer_messages_for_relay_parent<Context>(
|
||||
send_pending_grid_messages(
|
||||
ctx,
|
||||
relay_parent,
|
||||
&peer,
|
||||
&(peer, peer_data.protocol_version),
|
||||
validator_id,
|
||||
&per_session_state.groups,
|
||||
relay_parent_state,
|
||||
@@ -734,15 +754,34 @@ async fn send_peer_messages_for_relay_parent<Context>(
|
||||
fn pending_statement_network_message(
|
||||
statement_store: &StatementStore,
|
||||
relay_parent: Hash,
|
||||
peer: &PeerId,
|
||||
peer: &(PeerId, ValidationVersion),
|
||||
originator: ValidatorIndex,
|
||||
compact: CompactStatement,
|
||||
) -> Option<(Vec<PeerId>, net_protocol::VersionedValidationProtocol)> {
|
||||
statement_store
|
||||
.validator_statement(originator, compact)
|
||||
.map(|s| s.as_unchecked().clone())
|
||||
.map(|signed| protocol_v2::StatementDistributionMessage::Statement(relay_parent, signed))
|
||||
.map(|msg| (vec![*peer], Versioned::V2(msg).into()))
|
||||
match peer.1 {
|
||||
ValidationVersion::V2 => statement_store
|
||||
.validator_statement(originator, compact)
|
||||
.map(|s| s.as_unchecked().clone())
|
||||
.map(|signed| {
|
||||
protocol_v2::StatementDistributionMessage::Statement(relay_parent, signed)
|
||||
})
|
||||
.map(|msg| (vec![peer.0], Versioned::V2(msg).into())),
|
||||
ValidationVersion::VStaging => statement_store
|
||||
.validator_statement(originator, compact)
|
||||
.map(|s| s.as_unchecked().clone())
|
||||
.map(|signed| {
|
||||
protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, signed)
|
||||
})
|
||||
.map(|msg| (vec![peer.0], Versioned::VStaging(msg).into())),
|
||||
ValidationVersion::V1 => {
|
||||
gum::error!(
|
||||
target: LOG_TARGET,
|
||||
"Bug ValidationVersion::V1 should not be used in statement-distribution v2,
|
||||
legacy should have handled this"
|
||||
);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a peer all pending cluster statements for a relay parent.
|
||||
@@ -750,7 +789,7 @@ fn pending_statement_network_message(
|
||||
async fn send_pending_cluster_statements<Context>(
|
||||
ctx: &mut Context,
|
||||
relay_parent: Hash,
|
||||
peer_id: &PeerId,
|
||||
peer_id: &(PeerId, ValidationVersion),
|
||||
peer_validator_id: ValidatorIndex,
|
||||
cluster_tracker: &mut ClusterTracker,
|
||||
candidates: &Candidates,
|
||||
@@ -794,7 +833,7 @@ async fn send_pending_cluster_statements<Context>(
|
||||
async fn send_pending_grid_messages<Context>(
|
||||
ctx: &mut Context,
|
||||
relay_parent: Hash,
|
||||
peer_id: &PeerId,
|
||||
peer_id: &(PeerId, ValidationVersion),
|
||||
peer_validator_id: ValidatorIndex,
|
||||
groups: &Groups,
|
||||
relay_parent_state: &mut PerRelayParentState,
|
||||
@@ -856,20 +895,37 @@ async fn send_pending_grid_messages<Context>(
|
||||
candidate_hash,
|
||||
local_knowledge.clone(),
|
||||
);
|
||||
|
||||
messages.push((
|
||||
vec![*peer_id],
|
||||
Versioned::V2(
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateManifest(
|
||||
manifest,
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
match peer_id.1 {
|
||||
ValidationVersion::V2 => messages.push((
|
||||
vec![peer_id.0],
|
||||
Versioned::V2(
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateManifest(
|
||||
manifest,
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
)),
|
||||
ValidationVersion::VStaging => messages.push((
|
||||
vec![peer_id.0],
|
||||
Versioned::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(
|
||||
manifest,
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
)),
|
||||
ValidationVersion::V1 => {
|
||||
gum::error!(
|
||||
target: LOG_TARGET,
|
||||
"Bug ValidationVersion::V1 should not be used in statement-distribution v2,
|
||||
legacy should have handled this"
|
||||
);
|
||||
}
|
||||
};
|
||||
},
|
||||
grid::ManifestKind::Acknowledgement => {
|
||||
messages.extend(acknowledgement_and_statement_messages(
|
||||
*peer_id,
|
||||
peer_id,
|
||||
peer_validator_id,
|
||||
groups,
|
||||
relay_parent_state,
|
||||
@@ -1156,11 +1212,18 @@ async fn circulate_statement<Context>(
|
||||
(local_validator, targets)
|
||||
};
|
||||
|
||||
let mut statement_to = Vec::new();
|
||||
let mut statement_to_peers: Vec<(PeerId, ProtocolVersion)> = Vec::new();
|
||||
for (target, authority_id, kind) in targets {
|
||||
// Find peer ID based on authority ID, and also filter to connected.
|
||||
let peer_id: PeerId = match authorities.get(&authority_id) {
|
||||
Some(p) if peers.get(p).map_or(false, |p| p.knows_relay_parent(&relay_parent)) => *p,
|
||||
let peer_id: (PeerId, ProtocolVersion) = match authorities.get(&authority_id) {
|
||||
Some(p) if peers.get(p).map_or(false, |p| p.knows_relay_parent(&relay_parent)) => (
|
||||
*p,
|
||||
peers
|
||||
.get(p)
|
||||
.expect("Qed, can't fail because it was checked above")
|
||||
.protocol_version
|
||||
.into(),
|
||||
),
|
||||
None | Some(_) => continue,
|
||||
};
|
||||
|
||||
@@ -1178,11 +1241,11 @@ async fn circulate_statement<Context>(
|
||||
originator,
|
||||
compact_statement.clone(),
|
||||
);
|
||||
statement_to.push(peer_id);
|
||||
statement_to_peers.push(peer_id);
|
||||
}
|
||||
},
|
||||
DirectTargetKind::Grid => {
|
||||
statement_to.push(peer_id);
|
||||
statement_to_peers.push(peer_id);
|
||||
local_validator.grid_tracker.sent_or_received_direct_statement(
|
||||
&per_session.groups,
|
||||
originator,
|
||||
@@ -1193,17 +1256,23 @@ async fn circulate_statement<Context>(
|
||||
}
|
||||
}
|
||||
|
||||
let statement_to_v2_peers =
|
||||
filter_by_peer_version(&statement_to_peers, ValidationVersion::V2.into());
|
||||
|
||||
let statement_to_vstaging_peers =
|
||||
filter_by_peer_version(&statement_to_peers, ValidationVersion::VStaging.into());
|
||||
|
||||
// ship off the network messages to the network bridge.
|
||||
if !statement_to.is_empty() {
|
||||
if !statement_to_v2_peers.is_empty() {
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
?compact_statement,
|
||||
n_peers = ?statement_to.len(),
|
||||
"Sending statement to peers",
|
||||
n_peers = ?statement_to_v2_peers.len(),
|
||||
"Sending statement to v2 peers",
|
||||
);
|
||||
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
statement_to,
|
||||
statement_to_v2_peers,
|
||||
Versioned::V2(protocol_v2::StatementDistributionMessage::Statement(
|
||||
relay_parent,
|
||||
statement.as_unchecked().clone(),
|
||||
@@ -1212,6 +1281,25 @@ async fn circulate_statement<Context>(
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
if !statement_to_vstaging_peers.is_empty() {
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
?compact_statement,
|
||||
n_peers = ?statement_to_peers.len(),
|
||||
"Sending statement to vstaging peers",
|
||||
);
|
||||
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
statement_to_vstaging_peers,
|
||||
Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::Statement(
|
||||
relay_parent,
|
||||
statement.as_unchecked().clone(),
|
||||
))
|
||||
.into(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
/// Check a statement signature under this parent hash.
|
||||
fn check_statement_signature(
|
||||
@@ -1697,14 +1785,8 @@ async fn provide_candidate_to_grid<Context>(
|
||||
statement_knowledge: filter.clone(),
|
||||
};
|
||||
|
||||
let manifest_message =
|
||||
Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateManifest(manifest));
|
||||
let ack_message = Versioned::V2(
|
||||
protocol_v2::StatementDistributionMessage::BackedCandidateKnown(acknowledgement),
|
||||
);
|
||||
|
||||
let mut manifest_peers = Vec::new();
|
||||
let mut ack_peers = Vec::new();
|
||||
let mut manifest_peers: Vec<(PeerId, ProtocolVersion)> = Vec::new();
|
||||
let mut ack_peers: Vec<(PeerId, ProtocolVersion)> = Vec::new();
|
||||
|
||||
let mut post_statements = Vec::new();
|
||||
for (v, action) in actions {
|
||||
@@ -1712,7 +1794,7 @@ async fn provide_candidate_to_grid<Context>(
|
||||
None => continue,
|
||||
Some(p) =>
|
||||
if peers.get(&p).map_or(false, |d| d.knows_relay_parent(&relay_parent)) {
|
||||
p
|
||||
(p, peers.get(&p).expect("Qed, was checked above").protocol_version.into())
|
||||
} else {
|
||||
continue
|
||||
},
|
||||
@@ -1738,44 +1820,95 @@ async fn provide_candidate_to_grid<Context>(
|
||||
&per_session.groups,
|
||||
group_index,
|
||||
candidate_hash,
|
||||
&(p.0, p.1.try_into().expect("Qed, can not fail was checked above")),
|
||||
)
|
||||
.into_iter()
|
||||
.map(|m| (vec![p], m)),
|
||||
.map(|m| (vec![p.0], m)),
|
||||
);
|
||||
}
|
||||
|
||||
if !manifest_peers.is_empty() {
|
||||
let manifest_peers_v2 = filter_by_peer_version(&manifest_peers, ValidationVersion::V2.into());
|
||||
let manifest_peers_vstaging =
|
||||
filter_by_peer_version(&manifest_peers, ValidationVersion::VStaging.into());
|
||||
if !manifest_peers_v2.is_empty() {
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
?candidate_hash,
|
||||
local_validator = ?local_validator.index,
|
||||
n_peers = manifest_peers.len(),
|
||||
"Sending manifest to peers"
|
||||
n_peers = manifest_peers_v2.len(),
|
||||
"Sending manifest to v2 peers"
|
||||
);
|
||||
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
manifest_peers,
|
||||
manifest_message.into(),
|
||||
manifest_peers_v2,
|
||||
Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateManifest(
|
||||
manifest.clone(),
|
||||
))
|
||||
.into(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
if !ack_peers.is_empty() {
|
||||
if !manifest_peers_vstaging.is_empty() {
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
?candidate_hash,
|
||||
local_validator = ?local_validator.index,
|
||||
n_peers = ack_peers.len(),
|
||||
"Sending acknowledgement to peers"
|
||||
n_peers = manifest_peers_vstaging.len(),
|
||||
"Sending manifest to vstaging peers"
|
||||
);
|
||||
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
ack_peers,
|
||||
ack_message.into(),
|
||||
manifest_peers_vstaging,
|
||||
Versioned::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest),
|
||||
)
|
||||
.into(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
let ack_peers_v2 = filter_by_peer_version(&ack_peers, ValidationVersion::V2.into());
|
||||
let ack_peers_vstaging = filter_by_peer_version(&ack_peers, ValidationVersion::VStaging.into());
|
||||
if !ack_peers_v2.is_empty() {
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
?candidate_hash,
|
||||
local_validator = ?local_validator.index,
|
||||
n_peers = ack_peers_v2.len(),
|
||||
"Sending acknowledgement to v2 peers"
|
||||
);
|
||||
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
ack_peers_v2,
|
||||
Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateKnown(
|
||||
acknowledgement.clone(),
|
||||
))
|
||||
.into(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
if !ack_peers_vstaging.is_empty() {
|
||||
gum::debug!(
|
||||
target: LOG_TARGET,
|
||||
?candidate_hash,
|
||||
local_validator = ?local_validator.index,
|
||||
n_peers = ack_peers_vstaging.len(),
|
||||
"Sending acknowledgement to vstaging peers"
|
||||
);
|
||||
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage(
|
||||
ack_peers_vstaging,
|
||||
Versioned::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(
|
||||
acknowledgement,
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
if !post_statements.is_empty() {
|
||||
ctx.send_message(NetworkBridgeTxMessage::SendValidationMessages(post_statements))
|
||||
.await;
|
||||
@@ -2074,6 +2207,7 @@ fn post_acknowledgement_statement_messages(
|
||||
groups: &Groups,
|
||||
group_index: GroupIndex,
|
||||
candidate_hash: CandidateHash,
|
||||
peer: &(PeerId, ValidationVersion),
|
||||
) -> Vec<net_protocol::VersionedValidationProtocol> {
|
||||
let sending_filter = match grid_tracker.pending_statements_for(recipient, candidate_hash) {
|
||||
None => return Vec::new(),
|
||||
@@ -2090,14 +2224,29 @@ fn post_acknowledgement_statement_messages(
|
||||
recipient,
|
||||
statement.payload(),
|
||||
);
|
||||
|
||||
messages.push(Versioned::V2(
|
||||
protocol_v2::StatementDistributionMessage::Statement(
|
||||
relay_parent,
|
||||
statement.as_unchecked().clone(),
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
match peer.1.into() {
|
||||
ValidationVersion::V2 => messages.push(Versioned::V2(
|
||||
protocol_v2::StatementDistributionMessage::Statement(
|
||||
relay_parent,
|
||||
statement.as_unchecked().clone(),
|
||||
)
|
||||
.into(),
|
||||
)),
|
||||
ValidationVersion::VStaging => messages.push(Versioned::VStaging(
|
||||
protocol_vstaging::StatementDistributionMessage::Statement(
|
||||
relay_parent,
|
||||
statement.as_unchecked().clone(),
|
||||
)
|
||||
.into(),
|
||||
)),
|
||||
ValidationVersion::V1 => {
|
||||
gum::error!(
|
||||
target: LOG_TARGET,
|
||||
"Bug ValidationVersion::V1 should not be used in statement-distribution v2,
|
||||
legacy should have handled this"
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
messages
|
||||
@@ -2167,7 +2316,15 @@ async fn handle_incoming_manifest<Context>(
|
||||
};
|
||||
|
||||
let messages = acknowledgement_and_statement_messages(
|
||||
peer,
|
||||
&(
|
||||
peer,
|
||||
state
|
||||
.peers
|
||||
.get(&peer)
|
||||
.map(|val| val.protocol_version)
|
||||
// Assume the latest stable version, if we don't have info about peer version.
|
||||
.unwrap_or(ValidationVersion::V2),
|
||||
),
|
||||
sender_index,
|
||||
&per_session.groups,
|
||||
relay_parent_state,
|
||||
@@ -2198,7 +2355,7 @@ async fn handle_incoming_manifest<Context>(
|
||||
/// Produces acknowledgement and statement messages to be sent over the network,
|
||||
/// noting that they have been sent within the grid topology tracker as well.
|
||||
fn acknowledgement_and_statement_messages(
|
||||
peer: PeerId,
|
||||
peer: &(PeerId, ValidationVersion),
|
||||
validator_index: ValidatorIndex,
|
||||
groups: &Groups,
|
||||
relay_parent_state: &mut PerRelayParentState,
|
||||
@@ -2217,11 +2374,28 @@ fn acknowledgement_and_statement_messages(
|
||||
statement_knowledge: local_knowledge.clone(),
|
||||
};
|
||||
|
||||
let msg = Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateKnown(
|
||||
acknowledgement,
|
||||
let msg_v2 = Versioned::V2(protocol_v2::StatementDistributionMessage::BackedCandidateKnown(
|
||||
acknowledgement.clone(),
|
||||
));
|
||||
|
||||
let mut messages = vec![(vec![peer], msg.into())];
|
||||
let mut messages = match peer.1 {
|
||||
ValidationVersion::V2 => vec![(vec![peer.0], msg_v2.into())],
|
||||
ValidationVersion::VStaging => vec![(
|
||||
vec![peer.0],
|
||||
Versioned::VStaging(protocol_v2::StatementDistributionMessage::BackedCandidateKnown(
|
||||
acknowledgement,
|
||||
))
|
||||
.into(),
|
||||
)],
|
||||
ValidationVersion::V1 => {
|
||||
gum::error!(
|
||||
target: LOG_TARGET,
|
||||
"Bug ValidationVersion::V1 should not be used in statement-distribution v2,
|
||||
legacy should have handled this"
|
||||
);
|
||||
return Vec::new()
|
||||
},
|
||||
};
|
||||
|
||||
local_validator.grid_tracker.manifest_sent_to(
|
||||
groups,
|
||||
@@ -2238,9 +2412,10 @@ fn acknowledgement_and_statement_messages(
|
||||
&groups,
|
||||
group_index,
|
||||
candidate_hash,
|
||||
peer,
|
||||
);
|
||||
|
||||
messages.extend(statement_messages.into_iter().map(|m| (vec![peer], m)));
|
||||
messages.extend(statement_messages.into_iter().map(|m| (vec![peer.0], m)));
|
||||
|
||||
messages
|
||||
}
|
||||
@@ -2320,6 +2495,15 @@ async fn handle_incoming_acknowledgement<Context>(
|
||||
&per_session.groups,
|
||||
group_index,
|
||||
candidate_hash,
|
||||
&(
|
||||
peer,
|
||||
state
|
||||
.peers
|
||||
.get(&peer)
|
||||
.map(|val| val.protocol_version)
|
||||
// Assume the latest stable version, if we don't have info about peer version.
|
||||
.unwrap_or(ValidationVersion::V2),
|
||||
),
|
||||
);
|
||||
|
||||
if !messages.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user